Подтвердить что ты не робот

TDD: Это мешает хорошему дизайну API?

Я никогда не писал TDD-код, но я видел приличную дискуссию об этом здесь, на SO. Моя самая большая забота об этом заключается в том, что, похоже, общий дизайн API (для гибкости, простоты использования, простоты интерфейса и производительности) иногда занимает заднее место, чтобы сделать код макетным, ультра-модульным, помимо того, что необходимо для любого использования API case и т.д. Например, сторонники TDD часто предлагают, чтобы вещи передавались в качестве параметров, которые с точки зрения абстракции API вызываемый метод должен "просто знать" или что классы и методы будут учитываться таким образом, чтобы упростить тестирование, что не всегда является способом, который наилучшим образом относится к проблемной области.

Для людей, более опытных как с дизайном TDD, так и с API: вы обнаружите, что TDD часто мешает хорошему дизайну API? Если да, то как вы справляетесь с этим?

4b9b3361

Ответ 1

Я использую TDD уже несколько лет, и я обнаружил, что он управляет дизайном API для более удобного дизайна, предоставляя вам два разных клиента для API с самого начала; у вас есть производственный код и тестовый код, оба из которых хотят управлять API по-разному.

Это правда, что иногда я добавляю вещи ради упрощения тестирования API, но я почти всегда считаю, что вещи, которые, как мне кажется, я просто использую для проверки, на самом деле очень полезны для целей мониторинга. Так, например, FooAllocator может закончиться необязательным аргументом конструктора, который является интерфейсом мониторинга (IMonitorFooAllocations), который очень полезен для издевательства во время тестирования, чтобы я мог заглянуть внутрь, но который также имеет тенденцию очень полезно, когда вы вдруг обнаружите, что вам нужно выставлять некоторые показатели распределения для остального мира во время производства. Теперь я склонен думать о дополнительных битах, которые я могу добавить, чтобы обеспечить легкое тестирование с точки зрения их двойного использования для дополнительного мониторинга продукции. Я вообще пишу код сервера и могу разоблачить внутренние вещи, поскольку счетчики perfmon ОЧЕНЬ полезны...

Аналогичным образом вы правильно говорите, что часто объекты, составляющие API, могут принимать некоторые другие объекты явно, а не протягивать их и получать из известного места, но это хорошо. Поверьте мне, как только вы привыкнете к явным зависимостям, вам не захочется возвращаться к необходимости выкапывать класс после класса, чтобы выяснить, как и почему ваш Widgets обращается к активному каталогу, когда в API нет намека на то, что они будут хочу сделать такое. Также часто бывает, что вы нарушаете эти отношения зависимостей во время проектирования и тестирования, а затем спрятаете их снова, когда вы соедините все части. Вы все еще "параметризуете сверху", но чаще всего объектная модель API может означать, что вы никогда не видите "выше" как пользователя API. Вы получаете одно место для настройки API с теми вещами, которые ему нужны, и часто это ничем не отличается от того, как он выглядел бы, если бы у вас была масса синглетов и глобалов и скрытых зависимостей.

Но помните, TDD - это инструмент, когда он не подходит, не используйте его.

Ответ 2

Нет, я считаю, что TDD обычно поощряет хороший дизайн. Вещи, которые легко проверяются, часто просты в использовании в производстве... потому что, придумывая тест, вы думаете: "Что бы я хотел сделать дальше?" а затем заставьте его работать.

Когда вы практикуете TDD, вы вынуждены продумать "варианты использования" для API, как программист будет использовать классы/методы, и в итоге вы получите очень полезную структуру. Если вам нужно создать сотню FooFactory и BarAuthenticator s, или API станет "ультра модульным", как вы говорите, скорее всего, вы поймете, что при написании тестового кода и подумайте о том, как его упростить.

Что касается параметров и инъекций зависимостей - я обычно обнаруживаю, что зависимости становятся намного яснее с использованием TDD. Они обычно являются аргументами конструктора, а не аргументами метода, но дают понять, что для реализации API требуется аутентификатор, источник случайности и т.д. Полезен для понимания того, что он делает. Вы можете быть уверены, что код не попадет в сеть или удаленную базу данных где-то, потому что это скрывает эти вещи в ее реализации. Эти скрытые детали - вот что делает API трудным для использования в тестовой среде.

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

Хороший источник информации об инъекции зависимостей и TDD можно найти в Блог тестирования Google. Обратите особое внимание на сообщения Miško Hevery или посмотрите некоторые его видео на Youtube: Не смотрите на вещи и больше.

Ответ 3

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

Ответ 4

TDD - это технология проектирования API. Каждый раз, когда вы пишете unit test, вы либо создаете API в первый раз, либо используете ранее созданный API. Каждый из этих тестов позволяет вам "чувствовать", насколько легко или сложно использовать API. Каждый новый тест заставляет вас рассматривать API с новой точки зрения. Не может быть лучшего способа разработки API-интерфейсов, а не для исчерпывающего использования их, как TDD заставляет вас.

В самом деле, это причина, по которой TDD считается методикой проектирования, а не техникой тестирования. Когда вы практикуете TDD, вы не проектируете свои API в вакууме. Вы разрабатываете их, используя их!

Ответ 5

Большинство вещей, которые вы указали в качестве недостатков TDD, многими считаются элементами хорошего дизайна.

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

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

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

Ответ 6

Я использую TDD и считаю, что он хорошо работает в отношении построения API, но я думаю, что API, особенно те, которые вы предоставляете внешним клиентам, - это область, в которой вам требуется немного более авансированный дизайн, чем типичный при использовании TDD, TDD полагается так же сильно на рефакторинг, как и на тест-первых. С API вы не всегда обладаете роскошью как для рефакторинга ваших сигнатур методов, так и для чистого дизайна. Если вы не будете осторожны в разработке своего интерфейса, вы можете оказаться с уродливым интерфейсом, который поддерживает несколько методов, делающих очень похожие вещи, чтобы поддерживать обратную совместимость с вашим существующим API и в то же время перемещать ваш проект вперед.

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

Ответ 7

С традиционным дизайном API легко вставить себя в угол: вы можете получить API с множеством скрытых зависимостей (например, для потребностей класса A B требует C потребностей D и если вы измените порядок, в котором классы инициализируются, вещи начинают разрушаться).

TDD гарантирует, что отдельные части остаются отдельными. Он также позволяет вам видеть ваш API с очень необычной точки зрения: как пользователь/потребитель. Ваш первый вопрос: "Как я хочу использовать это?" а не "Как я хочу, чтобы API выглядел?" Последний может заманить вас в скрытую ловушку, в то время как первый приводит к чему-то, что я называю "интуитивно понятным API": он ведет себя так, как ожидалось.

Слово совета: не делайте TDD своей религией. Это инструмент и некоторые проблемы не могут быть решены с помощью некоторых инструментов. Поэтому, если TDD не работает для вас по какой-либо причине, тогда это нормально. Используйте столько TDD, сколько хотите. Не волнуйтесь об этом. На протяжении многих лет вы найдете свою зону комфорта.

Ответ 8

Вы можете взглянуть на newspeak работу на языке a.o. Gilad Bracha, чтобы увидеть некоторые соответствующие API и дизайн языка.

Ответ 9

Я согласен на 100% с верхними ответами. Но на самом деле это зависит от того, что вы подразумеваете под "хорошим дизайном API". TDD приводит к тестируемому, модульному рабочему коду, но в конечном итоге наиболее важным аспектом TDD-кода является тестируемость.

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

Во многих случаях имеет смысл использовать TDD для создания рабочего кода, а затем - как отдельный шаг - вытащить API. В противном случае у вас есть две силы, работающие несколько в конфликте: простой API и проверяемый код.

Это тонкая точка, однако, и общая TDD предоставит гораздо лучшие API, чем проектирование с башни из слоновой кости.

Ответ 10

Напротив, поскольку вы используете свои методы мышления как пользователя, написав ваши тесты, вы обнаружите проблемы, которые ваш пользователь придумает, когда вы его напишете. Фактически, у вас будет намного более чистый и удобный интерфейс, который вы бы написали иначе.

Ответ 11

Если ваш API страдает из-за внутренних требований ваших объектов, это то, для чего предназначен шаблон фасада. Не все объекты должны быть общедоступными.

Многие болевые точки TDD - это, по сути, признаки болевых точек в дизайне. Если сложно создать класс, потому что ему нужно передать 18 зависимостей, основная проблема заключается в том, что класс имеет слишком много зависимостей и будет довольно хрупким. Это также, вероятно, слишком много waaaaaay. "Боль TDD" в этом случае - это хорошо, поскольку это делает другие проблемы более очевидными.

Ответ 12

TDD не мешает хорошему дизайну API.

Отказывание препятствует хорошему дизайну API.

Оба не являются синонимами - я самостоятельно начал использовать TDD, прежде чем другие написали книги на нем, просто потому, что он ясно показывает, являются ли требования проверяемыми, а проекты отвечают требованиям.

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

Как противостоять: используйте TDD, но не используйте насмешку.

Ответ 13

Точка о TDD я sthat мы пишем тесты, которые вызывают код при его разработке. Следовательно, мы должны получить чрезвычайно удобный интерфейс. Конечно, это происходит не случайно. Мы по-прежнему должны сделать правильный выбор.

Ответ 14

Я не заметил, что TDD делает неправильные варианты API вообще.

Напротив, создавая четкую структуру, API, в первую очередь, более понятен и более понятен своим пользователям.