Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Оно (приложение) принимает события от сервера и реагирует на них некоторыми командами, поддерживая внутреннюю state машину ≤…> И это по сути всё.Как бы вы смогли сделать так обобщенное утверждение, не исследуя отдельные частные случаи (что сделали авторы книги в тестах с моками)? Если бы эти частные случаи не были бы разобраны достаточно подробно (в тестах с моками), как бы вы могли быть уверены, что ваше архитектурное решение правильное? Ну, и т.д. То есть, с одной стороны имеем открыто показанное (почти) во всех подробностях решение, иллюстрирующее общий метод, а с другой — из шляпы фокусника извлеченное лучшее (это, надеюсь, мы еще обсудим) решение. Собственно, вопрос: вы предлагаете какую-то свою методологию построения систем? Если да, в чем ее отличие от TDD/BDD, которые по сути следуют по «классическому» пути ООП (найди функциональность — найди (или создай) объект, в который эту функциональность надо поместить) на уровне анализа отдельных (а не обобщенных) требований.
вы не против разработки с моками? Вы просто призываете их удалить после того, как «реализация готова»?Это я к тому, что если вы большой приверженец подхода сверзу-вниз, то это тоже не повод оставлять моки в конечной имплементации.
Классика — это всегда bottom-up, Кент Бек и ко не писали про моки в оригинале, лондонская школа выработалась позже.А, вы о классике TDD? Я не сразу понял. Я-то о классике программирования :) — в книжках еще про структурных подход можно почитать.
Сочетать то, что описано в книге с классикой кстати возможно, но не так как вы описали (и это соответственно не будет полноценным top-down).Я бегло поискал по книге — они действительно об этом не пишут! То, как я это описал, работает — я так практикую уже несколько лет. Осталось выяснить, откуда я это взял :) Не сам же придумал! Был уверен, что вычитал данный подход именно в «Growing…»
Можно начать с набросков доменной модели (без тестов), затем после того как структура более-менее понятна — написать первый end-to-end тест и прокладывать себе путь к его исполнению путем классического bottom-up. Получится эдакий двух-уровневый TDD (как описано в книге), но без моков и без преждевременного распределения ответственностей. Проблема в top-down подходе в том, что если вы неверно выделелили эти ответственности, то отрефакторить их довольно сложно, т.к. из-за моков тесты становятся завязаны на детали имплементации.На практике часто все происходит с точностью до наоборот. Если «набросать структуру», то очень легко ошибиться, и ошибка часто выявляется уже на поздних стадиях: когда снизу-вверх «поднялись» до верхних уровней и вдруг оказалось, что модуль A должен использовать объекты из модуля B, но ничего про модуль B не знает, а чтобы узнал — нужно изменить (часто просто поломать) всю сложившуюся структуру. Очень огорчает и приводит к большим временным затратам.
Если «набросать структуру», то очень легко ошибитьсяСтурктура как раз-таки должна быть легковесной (отсюда слово «набросать»), чтобы ее можно было легко менять. Итерировать дизайн нужно в любом случае, разница в том, есть ли у вас при этом тесты и если есть — насколько хрупкие они.
Тесты с моками далеко не всегда оказываются такими уж хрупкимиТесты с моками не хрупки только когда они заменяют собой external systems (bus, БД и т.д). Если они мочат внутренности доменной модели — они завязываются на детали имплементации и значит становятся хрупкими. Сторонники mockist подхода (как минимум те, кого я встречал, включая авторов GOOS книги) не делают такого разделения и как правило мочат всё подряд — и внешние системы и внутренности самой доменной модели.
Тесты с моками не хрупки только когда они заменяют собой external systems (bus, БД и т.д).Это как раз тот случай, когда моки использовать не следует! Если, конечно, вы о моках говорите, а не о Test Doubles в общем виде.
Стурктура как раз-таки должна быть легковесной (отсюда слово «набросать»), чтобы ее можно было легко менять.Да понятно, что все должны быть богатыми и здоровыми. Вопрос в том, как этого добиться. Как работает TDD с моками и без, почему это так, где тут плюсы, а где минусы и т.д. — более-менее понятно (если этим долго и упорно заниматься). А вот откуда возьмется легковесная и легко изменяемая на протяжении всей жизни программной системы структура — не ясно. Может быть, она должна присниться (как якобы было с таблицей и Менделеевым)? Или нужно «съесть зубы» на архитектурах программного обеспечения? Или изучить все существующие архитектурные/дизайнерские паттерны? Развить в себе интуицию до уровня вангования чтобы наперед знать все возможные последствия того или иного принятого решения? Нужно познать смысл жизни? :) Я пока не увидел ответа, который мог бы работать для любого/обычного человека. Или, может быть, наоборот: не надо уделять этому вопросу лишнего внимания? «набросал» что первое пришло в голову и отдал кодерами — пусть сами мучаются со своей кодобазой, если через полгода выясниться, что эта простенькая структура не отвечает необходимым требованиям?
Итерировать дизайн нужно в любом случае, разница в том, есть ли у вас при этом тесты и если есть — насколько хрупкие они.Создается впечатление, что вы понимаете TDD как тестирование. И тесты для вас — какой-то ненужный артефакт, мешающий процессу разработки: закончили разработку — запустили (условно) один раз тесты, чтобы убедиться что все правильно — забыли про них.
найди функциональность — найди (или создай) объект, в который эту функциональность надо поместить
Действительно ли ваша система проще? Мне пока вы не смогли это продемонстрировать.Мне кажется, это довольно легко увидеть глядя на диаграммы + код. В альтернативной версии в два раза меньше классов и интерфейсов (при этом код внутри самих классов либо такой же по размеру, либо меньше), плюс он не имеет недостатков, описанных в статье, таких как наличие циклических зависимостей.
Это моки заставили авторов наделать столько классов (что сомнительно) или (что более вероятно) они принимали во внимание какие-то аспекты, которые вы по каким-то причинам откинули?Опять же, это легко проверить посмотрев на код.
возможно, компоненты действительно должны взаимодействовать «в обе стороны», а вы просто прячете это за возможностями какого-нибудь фреймворкаКак я уже упомянул, код проекта довольно несложен, никаких фреймворков за исключением UI не используется. Должны или нет взаимодействовать в обе стороны — на мой вгляд неверная постановка вопроса. Нужно смотреть на то, можно ли сделать так, чтобы они работали только в одну сторону. Если можно — значит так и нужно делать.
Отзыв на книгу Growing Object-Oriented Software, Guided by Tests