Что такое "простое решение"?
От: m_n Казахстан  
Дата: 07.08.06 14:04
Оценка:
В своей статье "Проектирования больше нет?" Мартин Фаулер приводит определение Кента Бека для простого решения:

В книге Extreme Programming Explained Кент приводит четыре критерия простой системы. Вот они в порядке убывания важности:

Система успешно проходит все тесты
Код системы ясно раскрывает все изначальные замыслы
В ней отсутствует дублирование кода
Используется минимально возможное количество классов и методов


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

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

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

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


Кто-нибудь может пояснить определение простоты Бека?
Или у кого есть другое определение/мнение о простоте?
Re: Что такое "простое решение"?
От: Eugene Beschastnov Россия http://eugenius-nsk.livejournal.com/
Дата: 07.08.06 14:36
Оценка: 9 (1)
Мне кажется, тут происходит смешивание понятий "простая для понимания" и "простая по структуре". Причём Бек явно использует первое значение, а ты — второе. И, хотя эти понятия часто коррелируют, это принципиально разные вещи: если "простой по структуре" — это объективный критерий (т.е. его можно формально определить без привлечения человеческого мнения), то "простой для понимания" — явно субъективный.
--
Бесчастнов Евгений
Re: Что такое "простое решение"?
От: Kamil Rafikov  
Дата: 07.08.06 15:28
Оценка: 9 (1)
под тем, что система проходит все тесты скорее всего имеется в виду то, что все состояния "конечного автомата", который представляет собою система, могут быть протестированы разумный промежуток времени разумным числом тестировщиков или тестировочных программ
Re: Что такое "простое решение"?
От: fmiracle  
Дата: 07.08.06 15:46
Оценка: 24 (4) +2
Здравствуйте, m_n, Вы писали:


m_n>Первый пункт, на мой взгляд, самый неуместный из всех (и самый важный по мнению Бека). Можно подумать, что если система проходит все тесты, она простая, а если нет — то сложная. Шутка Вообще же, о каких собственно тестах идет речь? Если о функциональных, то они тут ни при чем (и соответственно их результаты), потому что простота — это нефункциональное требование, а тестов (нефункциональных) на простоту пока не существует. Получается, что прохождение тестов не является критерием простоты. Более того, возникает вопрос, зачем вообще запускать систему, чтобы выяснить, простая она или сложная? Простота — это свойство дизайна и архитектуры, и простота должна определяться еще до запуска системы, через анализ исходного кода (в широком смысле) системы.


Ну как же так. Ессно, это же самое важный пункт, и если он не проходит, то и все остальные не имеют смысла.

Пример: Предположим такого требования нет.
Я предлагаю очень простое решение для оценки вероятности попадания баллистической ракеты в цель, исходя из всех заданных параметров — дальность, ТТХ, помехи, защита, и прочее (сложная задача, надо сказать):

double HitProbability( object[] allParams)
{
  return 45.6;
}


По-моему — очень простое решение Кратко и ясно
Все прочие можно смело отправлять на помойку

Так что.
В первую очередь программа должна решать поставленную задачу. Точка. Самая замечательная программа, которая решает задачу неправильно, в бесконечность раз хуже самой кривой и запутанной, которая решает задачу правильно. Это как-то не должно вызывать вопросов. И сравнивать между собой имеет смысл только правильные решения. Единственный способ хоть как-то предположить правильность решения — тесты. Они ничего не гарантируют, конечно, но это хоть какая-то проверка.


Вот. Все остальное по топику — ты сам себя путаешь Ну нет в мире определения ни одной простой вещи. На самом деле можно лишь сказать что "это решение простое по сравнению с вот этим решением". Когда говорят только "простое решение", то имеют в виду, что сложно будет подобрать решение еще более простое чем это.
Таким образом можно правильно перефразировать определение:
— система с меньшим количеством дублируемого кода проще, чем истема с большим количеством дублируемого кода
— система с меньшим числом классов проще системы с большим числом классов
— система, с более понятным кодом проще, чем с менее понятным кодом запутанным кодом. (это субъективное мнение. тут я согласен, еще внизу выскажу)

Получив же в руки сравнение систем может говорить:
1. Это решение — проще вон того
2. Это решение — примерно так же просто как вон то.
3. Это решение — самое простое (тут просто невозможно уже уменьшить число классов и кода и т.д) (В реальности думаю только для совсем малых систем применимо)
4. Это решение — простое. То есть можно попробовать его еще упростить, но в результате получится примерно то же самое, только другими словами, может чуть проще или сложнее.

Вот и все.

З.Ы.
А вот "понятность" кода — это, конечно засада. Очень субъъективно. Сам сталкивался, когда один и тот же код один человек считает простым и ясным, а другой — сложным и запутанным То есть бывает такой код — про который явно сразу большинство народу скажет, что это отстой полный. А вот "хороший код" — дело сложнее. Тут сильно влияет как человек привык писать. Все, что непривычно — всегда кажется неудобным и неправильным, особенно на первый взгляд. Отсюда и возникают всевозможные стандарты кодирования, поддержка которых требуется при выполнении проекта.
Re: Что такое "простое решение"?
От: A.Lokotkov Россия http://www.linkedin.com/pub/alexander-lokotkov/a/701/625
Дата: 07.08.06 16:14
Оценка:
Здравствуйте, m_n, Вы писали:

m_n>Кто-нибудь может пояснить определение простоты Бека?

m_n>Или у кого есть другое определение/мнение о простоте?

Характерно, что в своей книжке Extreme Programming Explained он также определяет четыре критерия простоты решения. 2-й и 3-й аналогичны приведенным. Первый: понятность для целевой аудитории (хе-хе) -- если те, кому придется иметь дело с решением, чего-то не понимают, решение не является простым для них. Четвертый: с учетом названных выше трех ограничений система должна содержать наименьшее количество элементов (видимо, подразумевается, что взаимосвязи между элементами также являются элементами).

Думаю, вполне можно было бы ограничиться 4-м критерием.
bloß it hudla
Re[2]: Что такое "простое решение"?
От: ZevS Россия  
Дата: 08.08.06 06:53
Оценка:
Здравствуйте, fmiracle, Вы писали:

[...]

F>Так что.

F>В первую очередь программа должна решать поставленную задачу. Точка. Самая замечательная программа, которая решает задачу неправильно, в бесконечность раз хуже самой кривой и запутанной, которая решает задачу правильно. Это как-то не должно вызывать вопросов. И сравнивать между собой имеет смысл только правильные решения. Единственный способ хоть как-то предположить правильность решения — тесты. Они ничего не гарантируют, конечно, но это хоть какая-то проверка.

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

F>Вот. Все остальное по топику — ты сам себя путаешь Ну нет в мире определения ни одной простой вещи. На самом деле можно лишь сказать что "это решение простое по сравнению с вот этим решением". Когда говорят только "простое решение", то имеют в виду, что сложно будет подобрать решение еще более простое чем это.

F>Таким образом можно правильно перефразировать определение:
F>- система с меньшим количеством дублируемого кода проще, чем истема с большим количеством дублируемого кода
F>- система с меньшим числом классов проще системы с большим числом классов
F>- система, с более понятным кодом проще, чем с менее понятным кодом запутанным кодом. (это субъективное мнение. тут я согласен, еще внизу выскажу)

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

F>Получив же в руки сравнение систем может говорить:

F>1. Это решение — проще вон того

Ну конечно же! Мы же сами То выбрали.

F>2. Это решение — примерно так же просто как вон то.

F>3. Это решение — самое простое (тут просто невозможно уже уменьшить число классов и кода и т.д) (В реальности думаю только для совсем малых систем применимо)

А вот это не факт. Любую задачу можно решить с помощью одного единственного класса, или даже без него.

F>4. Это решение — простое. То есть можно попробовать его еще упростить, но в результате получится примерно то же самое, только другими словами, может чуть проще или сложнее.


F>Вот и все.


F>З.Ы.

F>А вот "понятность" кода — это, конечно засада. Очень субъъективно. Сам сталкивался, когда один и тот же код один человек считает простым и ясным, а другой — сложным и запутанным То есть бывает такой код — про который явно сразу большинство народу скажет, что это отстой полный. А вот "хороший код" — дело сложнее. Тут сильно влияет как человек привык писать. Все, что непривычно — всегда кажется неудобным и неправильным, особенно на первый взгляд. Отсюда и возникают всевозможные стандарты кодирования, поддержка которых требуется при выполнении проекта.

На мой взгляд в книге про рефакторинг тот же Фаулер показывает какой должна быть простая система. Покрайней мере, намечает путь.
Re[2]: Что такое "простое решение"?
От: buriy Россия http://www.buriy.com/
Дата: 08.08.06 07:10
Оценка:
Здравствуйте, Kamil Rafikov, Вы писали:

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


Полностью согласен. Тесты стоит писать так, чтобы максимизировать степень покрытия кода программы. Чтобы протестировать, насколько возможно, состояния этого большого конечного автомата.
/bur
Re[2]: Что такое "простое решение"?
От: m_n Казахстан  
Дата: 08.08.06 09:49
Оценка:
Здравствуйте, fmiracle, Вы писали:

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



m_n>>Первый пункт, на мой взгляд, самый неуместный из всех (и самый важный по мнению Бека). Можно подумать, что если система проходит все тесты, она простая, а если нет — то сложная. Шутка Вообще же, о каких собственно тестах идет речь? Если о функциональных, то они тут ни при чем (и соответственно их результаты), потому что простота — это нефункциональное требование, а тестов (нефункциональных) на простоту пока не существует. Получается, что прохождение тестов не является критерием простоты. Более того, возникает вопрос, зачем вообще запускать систему, чтобы выяснить, простая она или сложная? Простота — это свойство дизайна и архитектуры, и простота должна определяться еще до запуска системы, через анализ исходного кода (в широком смысле) системы.


F>Ну как же так. Ессно, это же самое важный пункт, и если он не проходит, то и все остальные не имеют смысла.


F>...


F>Так что.

F>В первую очередь программа должна решать поставленную задачу.

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

Следовательно, прохождение функциональных тестов не позволяет отличить простую систему от сложной, отказоустойчивую от уязвимой, быструю от медленной и т.д. Прохождение тестов позволяет лишь отличить программу, от, скажем так, не-программы (ну или алгоритм от не-алгоритма), т.е. грубо говоря, доказать ее завершимость и результативность. Доказать простоту системы может только тест на простоту (которого пока не существует), также, например, как и доказать нужный уровень производительности может только нефункциональный тест на производительность. Никто ведь не утверждает, что если система проходит все функциональные тесты, значит и ее производительноть (нефункциональное требование) находится на нужном уровне?
Re[3]: Что такое "простое решение"?
От: ZevS Россия  
Дата: 08.08.06 11:55
Оценка:
Здравствуйте, buriy, Вы писали:

[..]

B>Полностью согласен. Тесты стоит писать так, чтобы максимизировать степень покрытия кода программы. Чтобы протестировать, насколько возможно, состояния этого большого конечного автомата.


Тест покрывающий весь код, может не покрывать всех состояний.
Re: Что такое "простое решение"?
От: GlebZ Россия  
Дата: 08.08.06 14:32
Оценка: 4 (1) +1
Здравствуйте, m_n, Вы писали:

m_n>Первый пункт, на мой взгляд, самый неуместный из всех (и самый важный по мнению Бека). Можно подумать, что если система проходит все тесты, она простая, а если нет — то сложная. Шутка Вообще же, о каких собственно тестах идет речь?

Тестируемость системы означает наличие ясного и функционального интерфейса. Если подсистема не содержит интерфейса через который ее можно проверить, то она не является тестируемой. Это нормальное требование к архитектуре и дизайну для подсистем.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Что такое "простое решение"?
От: buriy Россия http://www.buriy.com/
Дата: 09.08.06 06:30
Оценка:
Здравствуйте, ZevS, Вы писали:

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


ZS>[..]


B>>Полностью согласен. Тесты стоит писать так, чтобы максимизировать степень покрытия кода программы. Чтобы протестировать, насколько возможно, состояния этого большого конечного автомата.


ZS>Тест покрывающий весь код, может не покрывать всех состояний.


Упс, ты прав. Побочные эффекты.
/bur
Re[5]: Что такое "простое решение"?
От: fmiracle  
Дата: 09.08.06 08:33
Оценка:
Здравствуйте, buriy, Вы писали:

B>>>Полностью согласен. Тесты стоит писать так, чтобы максимизировать степень покрытия кода программы. Чтобы протестировать, насколько возможно, состояния этого большого конечного автомата.

ZS>>Тест покрывающий весь код, может не покрывать всех состояний.

B>Упс, ты прав. Побочные эффекты.


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

Упрощенный пример:

int SomeMethod( int a, int b )
{
    c = 10;
    if( a > 0 )
    {
        c -= 5;
    }
    if( b > 0 )
    {
        c -= 5;
    }
    if( a + b == 2 ) return 1;
    return 20 / c;
}


Делаем тесты:
SomeMethod( 0, 0 )
SomeMethod( 0, 1 )
SomeMethod( 1, 0 )
SomeMethod( 1, 1 )

Как видно, эти тесты в сумме покрывают весь код метода. 100% покрытие тестами
Но они нифига не отлавливают, что при SomeMethod( 2, 2) будет деление на ноль.

Пример очень утрированный, чтобы было видно, но в реальности все только хуже, просто не так очевидно Но идея должна быть понятна — если один тест протестировал ветки 1 и 2, второй 2 и 3, третий 1 и 3, то это еще не значит, что выполнение веток 1-2-3 даст корректный результат. В общем, полагать, что если код покрыт на 100% тестами, то все протестировано — неправильно и опасно, ибо ведет к ложной уверенности.
Можно быть уверенным, если тесты покрывают 100% путей выполнения кода, но достичь этого на практике нереально — будет комбинаторный взрыв количества необходимых тестов.
Re[4]: Что такое "простое решение"?
От: Eugene Beschastnov Россия http://eugenius-nsk.livejournal.com/
Дата: 09.08.06 08:36
Оценка:
Здравствуйте, ZevS, Вы писали:

ZS>Тест покрывающий весь код, может не покрывать всех состояний.

Это да (*). Но тесты, не покрывающие весь код, с гарантией не покрывают все состояния. За исключением случаев, когда есть никогда не исполняющиеся участки кода — но такое надо находить и искоренять.

(*) тут есть еще такой нюанс — система, хорошо приспособленная к тестированию, состоит из практически независимых достаточно мелких единиц — а это условия, уменьшающие вероятность возникновения интерференции.
--
Бесчастнов Евгений
Re[6]: Что такое "простое решение"?
От: Eugene Beschastnov Россия http://eugenius-nsk.livejournal.com/
Дата: 09.08.06 08:47
Оценка:
Здравствуйте, fmiracle, Вы писали:

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

На основании своей практики могу сказать, что при достаточно хорошей минимизации тестируемых модулей среднее количество возможных путей исполнения в модуле — 3-4. Это вполне покрывается тестами и никакого комбинаторного взрыва не происходит. Но с утверждением
> В общем, полагать, что если код покрыт на 100% тестами, то все протестировано — неправильно и опасно, ибо ведет к ложной уверенности.
я соглашусь полностью. Я бы даже усилил его — "Даже если код покрыт тестами на 100%, то нельзя считать, что в программе нет ошибок". Но сразу сделаю оговорку — если код покрыт тестами на 100% и эти тесты хороши с точки зрения модульного тестирования, то вероятность существования ошибок в программе очень мала.
--
Бесчастнов Евгений
Re[6]: Что такое "простое решение"?
От: buriy Россия http://www.buriy.com/
Дата: 09.08.06 09:28
Оценка:
Здравствуйте, fmiracle, Вы писали:

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


B>>>>Полностью согласен. Тесты стоит писать так, чтобы максимизировать степень покрытия кода программы. Чтобы протестировать, насколько возможно, состояния этого большого конечного автомата.

ZS>>>Тест покрывающий весь код, может не покрывать всех состояний.

B>>Упс, ты прав. Побочные эффекты.


F>Да нет, тут основную проблему вызывает различная последовательность действий в коде при разных условиях...

Ах, да. Еще есть неявные действия языка программирования.

F>Упрощенный пример:


F>
F>int SomeMethod( int a, int b )
F>{
F>    c = 10;
F>    if( a > 0 )
F>    {
F>        c -= 5;
F>    }
F>    if( b > 0 )
F>    {
F>        c -= 5;
F>    }
F>    if( a + b == 2 ) return 1;
F>    return 20 / c;
F>}
F>


F>Делаем тесты:

F>SomeMethod( 0, 0 )
F>SomeMethod( 0, 1 )
F>SomeMethod( 1, 0 )
F>SomeMethod( 1, 1 )

F>Как видно, эти тесты в сумме покрывают весь код метода. 100% покрытие тестами

F>Но они нифига не отлавливают, что при SomeMethod( 2, 2) будет деление на ноль.
Абсолютно верно. Это и есть ПРАВИЛЬНОЕ ПОВЕДЕНИЕ кода на C# по умолчанию — выкидывание исключения при ошибке деления на 0.
F>Пример очень утрированный, чтобы было видно, но в реальности все только хуже, просто не так очевидно Но идея должна быть понятна — если один тест протестировал ветки 1 и 2, второй 2 и 3, третий 1 и 3, то это еще не значит, что выполнение веток 1-2-3 даст корректный результат. В общем, полагать, что если код покрыт на 100% тестами, то все протестировано — неправильно и опасно, ибо ведет к ложной уверенности.
Проблема имеет место быть, но относится она к другой ветке — "20 / с", неявно работающей в коде на C#.

Если ты хочешь написать тест, который проверяет, что код корректно обрабатывает деление на 0, ты можешь изменить код, чтобы в нем это было описано явно:
int SomeMethod( int a, int b )
{
    c = 10;
    if( a > 0 )
    {
        c -= 5;
    }
    if( b > 0 )
    {
        c -= 5;
    }
    if( a + b == 2 ) return 1;
    if( c != 0) {
        return 20 / c;
    } else {
        assert(false); // не помню как написать эту строчку на C#
    }
}

F>Можно быть уверенным, если тесты покрывают 100% путей выполнения кода, но достичь этого на практике нереально — будет комбинаторный взрыв количества необходимых тестов.
Тогда опять же комбинаторного взрыва не будет.
/bur
Re[2]: Что такое "простое решение"?
От: m_n Казахстан  
Дата: 09.08.06 12:26
Оценка:
Здравствуйте, GlebZ, Вы писали:

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


m_n>>Первый пункт, на мой взгляд, самый неуместный из всех (и самый важный по мнению Бека). Можно подумать, что если система проходит все тесты, она простая, а если нет — то сложная. Шутка Вообще же, о каких собственно тестах идет речь?

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

Другая ветка
Автор: m_n
Дата: 08.08.06
, но думаю, идея та же.
Re[3]: Что такое "простое решение"?
От: GlebZ Россия  
Дата: 09.08.06 12:53
Оценка:
Здравствуйте, m_n, Вы писали:

m_n>Другая ветка
Автор: m_n
Дата: 08.08.06
, но думаю, идея та же.

Критерий простоты — абстрактен. Критерий наличия интерфейса — строг. Тестируемость совсем не обозначает что все тесты должны пройти и программа должна работать. Тестируемость всего лишь наличие интерфейса работы подсистемы. Остальное, то что его можно протестить, уже вытекает из данного критерия.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Что такое "простое решение"?
От: ZevS Россия  
Дата: 09.08.06 13:58
Оценка:
Здравствуйте, fmiracle, Вы писали:

[...]

F>Можно быть уверенным, если тесты покрывают 100% путей выполнения кода, но достичь этого на практике нереально — будет комбинаторный взрыв количества необходимых тестов.


Мне нравится термин покрытие кода и входных данных. На практике полностью покрыть данные можно лишь в тривиальных ситуациях. Идеальным тестом можно считать тест покрывающтй 100% кода и максимум типовых вариантов входных данных. Самое сложное здесь — выбор типовых вариантов входных данных. Хотя это уже офтоп пошел...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.