пятница, 10 января 2014 г.

Лирика. "TDD" как обратная сторона "квадратов"

Про "квадраты" и "стрелки" я немного поразглагольствовал вот тут - http://programmingmindstream.blogspot.ru/2014/01/uml.html

Теперь хочется немного "полить воду" про мою ЛЮБИМУЮ тему - "разработка через тестирование".

Или "разработка на костылях тестов" :-) что - ВЕРНЕЕ.

Ну во-первых "хорошая тестируемость классов ведёт к хорошей их архитектуре".

Про это писал Тепляков:
http://programmingmindstream.blogspot.ru/2014/01/blog-post_3560.html
http://programmingmindstream.blogspot.ru/2014/01/blog-post_626.html

И ещё один автор:
http://18delphi.blogspot.ru/2013/11/blog-post_1441.html

Приведённые выше авторы озвучили ОДНУ "банальную" мысль, о которой я ДОЛГО думал, но никак не смог озвучить САМ.

А именно:
"Лакмусовая бумажка архитектурного решения
Я неоднократно писал о лакмусовой бумажке хорошего дизайна. Когда я рассматриваю дизайн класса или модуля, то стараюсь понять насколько он является цельным и слабосвязным (все те же low coupling и high cohesion) с помощью юнит-тестов. Если их написать невозможно или они будут невменяемыми, то это говорит мне, что с дизайном что-то не то.
А как определить качество архитектурного решения? Чтобы понять, как далеко некоторое решение проникло (или проникнет) в разные части системы, я задаю себе такой вопрос: «А что если я ошибся и мне придется изменить это решение в будущем? Какие будут последствия?». Если некоторое решение размазано ровным слоем по всему приложению, то стоимость его изменения будет огромной, а значит это решение является архитектурным."

Повторю ЕЩЁ раз. Как Я САМ это понимаю - "хорошо спроектированный класс - хорошо тестируется и НАОБОРОТ хорошо тестируемый класс - ХОРОШО спроектирован".

Ну ТАК я ДЛЯ СЕБЯ это ТЕПЕРЬ понимаю.

Примеров "из жизни" - у меня есть масса. Поверьте мне на слово :-) Для "особо интересующихся" - я могу попробовать собрать "дайджест".

Кстати слово "класс", тут не стоит воспринимать БУКВАЛЬНО. За ним может "маскироваться" и реальный проектный класс, и библиотека, и подсистема и проект.

Но это не всё что я хотел сказать.

Хочу сказать ещё одну "банальную" мысль. Уже НЕ РАЗ повторенную "классиками", но я ПРОЧУВСТВОВАЛ её на СЕБЕ.

Тесты это НЕ ТОЛЬКО (да и не столько) способ "поверки" правильности кода и его соответствия ТЗ.

Тесты это ещё и "пример использования" проектных классов и архитектурных решений.

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

Но! ПОСКОЛЬКУ этот код ХОРОШО и плотно покрыт тестами - мне и НЕ НАДО "его помнить".

Я ВСЕГДА могу посмотреть на ТЕСТЫ и понять - "как это работает" и "зачем это нужно".

ВСЁ! Мне НЕ НАДО "помнить код" и его детали.

Мне ДОСТАТОЧНО взят тесты и "перезагрузить" мой "кеш мозга".

ОЧЕНЬ УДОБНО. Для МЕНЯ ЛИЧНО.

Если кому-то этот подход - ИНТЕРЕСЕН - обращайтесь - могу попробовать и вас "прозомбировать".

P.S. А тут за рамками "выступления" осталось "аспектно-ориентированное программирование".

P.P.S. в том же самом проекте, где "нет UML" - нет и "нормальных тестов". И отчасти поэтому - он "тяжело программируется". Хотя и в РАЗЫ меньше других проектов.

5 комментариев:

  1. Тесты как примеры, которые показывают КАК использовать тестируемый код, и которые показывают ЧТО тестируемый код делает -- это ОЧЕНЬ классная мысль. И сильная..
    Спасибо )

    ОтветитьУдалить
  2. :-) пожалуйста :-)
    хотя конечно "это не я придумал"...

    Но!

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

    ОтветитьУдалить
  3. Ну и конечно - у нас тесты гоняются КАЖДЫЙ ДЕНЬ - посему никакая функциональность "не протухает", она либо ПОДДЕРЖИВАЕТСЯ, либо ВЫКИДЫВАЕТСЯ за ненадобностью.

    ОтветитьУдалить
  4. Знание становится научным, если оно инвариантно относительно контекста (либо контекст достаточно широкий).

    Пишем тест к классу, пишем класс. Вопрос: если мы НЕ пишем класс. Де-факто TDD в данной интерпретации жёстко накладывает условия по части выборе объектной парадигмы.

    Начинают вырисовываться чертежи большой торпеды в корабль Delphi (в каноническом виде дизайн-проекта): Form1->Button1->OnClick. У нас НЕТ класса (класс формы, понятно, не в счет). Нет класса - нет теста. Нет теста - нет TDD. Шанс спастись от этой торпеды - сделать "летучий корабль". Можно ли применить модель TDD к не-классово-объектной функциональности?

    И, конечно, нельзя не лягнуть "классиков". (цитата)
    "«А что если я ошибся и мне придется изменить это решение в будущем? Какие будут последствия?». Если некоторое решение размазано ровным слоем по всему приложению, то стоимость его изменения будет огромной, а значит это решение является архитектурным.""

    Делать заключение о качестве архитектуры на основе возможности тестирования отдельных элементов???? Модифицируемость - лишь один из показателей нефункционального качества. Жесткость связей гарантирует стабильную простоту системы.
    Не верите? Тогда - зеркало в студию.
    DBGrid->DataSource->TDataSet - очень жёстко. Как только предложили LiveBindings, пошла волна протестов (понятно, почему). Отсюда простой вывод. "Качество архитектурного решения из-за ослабления "контроля" достигается за счёт дополнительных усилий". Разумно ли их тратить? Если технологическое устаревание опережает сроки пересмотра архитектуры.... зачем огород городить? Возникает метафора "золотого унитаза" :)

    Итак, господа, на повестке дня 2 вопроса:
    1) TDD вне объектно-ориентированного программирования (но - object-based, form1...button1...onclick1)
    2) ошибки классиков или "переусложенная" архитектура

    ОтветитьУдалить
    Ответы
    1. "Пишем тест к классу, пишем класс. Вопрос: если мы НЕ пишем класс."
      мы ВСЕГДА пишем КЛАСС - класс функциональности
      а не класс в терминах ООП

      "DBGrid->DataSource->TDataSet - очень жёстко"
      и ПЛОХО ТЕСТИРУЕМО.. факт

      "Разумно ли их тратить?"
      ДАЛЕКО НЕ ВСЕГДА разумно
      тут вопрос встаёт - "а какой цикл модификации/поддержки кода"
      если мы его "вообще не трогаем", то наверное ИМЕННО этот код и не надо тестировать

      Удалить