Предположим, у нас есть метод, foo(String bar)
который работает только со строками, которые соответствуют определенным критериям; например, он должен быть в нижнем регистре, не должен быть пустым или иметь только пробел и должен соответствовать шаблону [a-z0-9-_./@]+
. Документация для метода устанавливает эти критерии.
Должен ли метод отклонять какие-либо отклонения от этого критерия или метод должен быть более щадящим по некоторым критериям? Например, если начальный метод
public void foo(String bar) {
if (bar == null) {
throw new IllegalArgumentException("bar must not be null");
}
if (!bar.matches(BAR_PATTERN_STRING)) {
throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
}
this.bar = bar;
}
И второй способ прощения
public void foo(String bar) {
if (bar == null) {
throw new IllegalArgumentException("bar must not be null");
}
if (!bar.matches(BAR_PATTERN_STRING)) {
bar = bar.toLowerCase().trim().replaceAll(" ", "_");
if (!bar.matches(BAR_PATTERN_STRING) {
throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
}
}
this.bar = bar;
}
Следует ли изменить документацию, указав, что она будет преобразована и по возможности установлена на преобразованное значение, или метод должен быть максимально простым и отклонять любые отклонения? В этом случае bar
может быть установлено пользователем приложения.
Основным вариантом использования для этого будут пользователи, которые обращаются к объектам из хранилища по определенному строковому идентификатору. Каждый объект в хранилище должен иметь уникальную строку для его идентификации. Эти репозитории могут хранить объекты различными способами (sql server, json, xml, binary и т. Д.), Поэтому я попытался определить наименьший общий знаменатель, который соответствовал бы большинству соглашений об именах.
источник
foo
функцию, которая строго соответствует аргументам, которые она принимает, и иметь вторую вспомогательную функцию, которая может попытаться «очистить» аргумент, который будет использоватьсяfoo
. Таким образом, у каждого метода меньше работы, и они могут более четко управляться и интегрироваться. Если идти по этому пути, вероятно, было бы также полезно отойти от тяжелого дизайна;Optional
вместо этого вы можете использовать что-то подобное , а затем иметь функции, которые потребляютfoo
исключения исключений, если это необходимо.Ответы:
Ваш метод должен делать то, что говорит.
Это предотвращает ошибки, как от использования, так и от сопровождающих, изменяющих поведение позже. Это экономит время, потому что сопровождающим не нужно тратить столько времени на выяснение того, что происходит.
Тем не менее, если определенная логика не удобна для пользователя, возможно, ее следует улучшить.
источник
foo
иfooForUncleanString
методы, где последний вносит исправления, прежде чем передать его первому.)Есть несколько моментов:
Помните, что существуют отладочные утверждения для диагностики логических ошибок в режиме отладки, которые в основном устраняют любые проблемы с производительностью.
Если вы реализуете пользовательский интерфейс, дружественные сообщения об ошибках (включая предложения и другую помощь) являются частью хорошего дизайна.
Но помните, что API-интерфейсы предназначены для программистов, а не конечных пользователей.
Настоящим экспериментом по нечеткости и разрешению ввода является HTML.
Это привело к тому, что все делали это немного по-разному, и спецификация, теперь она задокументирована, была гигантским томом, полным особых случаев.
См . Закон Постеля (« Будь консервативен в том, что ты делаешь, будь либеральным в том, что ты принимаешь от других »), и критик, касающийся этого ( или гораздо лучший, о котором Майкл Т дал мне знать ).
источник
Поведение метода должно быть четким, интуитивным, предсказуемым и простым. В общем, мы должны очень неохотно делать дополнительную обработку входных данных вызывающей стороны. Такие предположения о том, что подразумевал вызывающий, неизменно имеют множество крайних случаев, которые приводят к нежелательному поведению. Рассмотрим операцию так же просто, как присоединение пути к файлу. Многие (или, возможно, даже большинство) функций присоединения путей к файлам будут молча отбрасывать любые предшествующие пути, если один из соединяемых путей окажется корневым! Например,
/abc/xyz
соединение с/evil
приведет к просто/evil
. Это почти никогда не то, что я имею в виду, когда присоединяюсь к путям к файлам, но поскольку нет интерфейса, который не ведет себя таким образом, я вынужден либо иметь ошибки, либо писать дополнительный код, покрывающий эти случаи.Тем не менее, есть редкие случаи, когда имеет смысл «прощать» метод, но вызывающий всегда должен решать, когда и будут ли эти шаги обработки применяться к их ситуации. Поэтому, когда вы определили общий этап предварительной обработки, который вы хотите применить к аргументам в различных ситуациях, вы должны предоставить интерфейсы для:
Последнее не является обязательным; Вы должны предоставить его, только если большое количество звонков будет использовать его.
Предоставление необработанных функциональных возможностей дает вызывающей стороне возможность использовать их без шага предварительной обработки, когда это необходимо. Раскрытие шага препроцессора само по себе позволяет вызывающей стороне использовать его в ситуациях, когда они даже не вызывают функцию или когда они хотят предварительно обработать некоторый ввод перед вызовом функции (например, когда они хотят сначала передать его в другую функцию). Предоставление комбинации позволяет вызывающим абонентам вызывать оба без каких-либо хлопот, что полезно в первую очередь, если большинство вызывающих абонентов будут использовать его таким образом.
источник
Как уже говорили другие, сделать соответствие строк «прощающим» означает внести дополнительную сложность. Это означает больше работы по реализации сопоставления. Например, теперь у вас есть еще много тестов. Вы должны выполнить дополнительную работу, чтобы гарантировать отсутствие семантически равных имен в пространстве имен. Большая сложность также означает, что в будущем будет больше ошибок. Более простой механизм, такой как велосипед, требует меньше обслуживания, чем более сложный, такой как автомобиль.
Так стоит ли мягкое сопоставление строк столько дополнительных затрат? Это зависит от варианта использования, как отметили другие. Если строки представляют собой какой-то внешний вход, который вы не можете контролировать, и есть определенное преимущество для мягкого сопоставления, это может стоить того. Возможно, исходят от конечных пользователей, которые могут не очень внимательно относиться к пробелам и заглавным буквам, и у вас есть сильный стимул сделать ваш продукт более простым в использовании.
С другой стороны, если бы входные данные поступали, скажем, из файлов свойств, собранных техническими специалистами, которые должны это понимать
"Fred Mertz" != "FredMertz"
, я был бы более склонен сделать соответствие более строгим и сэкономить на стоимости разработки.Я думаю, что в любом случае имеет смысл обрезать и игнорировать начальные и конечные пробелы, хотя я видел слишком много часов, потраченных на отладку подобных проблем.
источник
Вы упоминаете некоторые из контекста, из которого возникает этот вопрос.
Учитывая это, я хотел бы, чтобы метод делал только одну вещь: он устанавливает требования к строке, пусть он исполняется на основе этого - я бы не пытался преобразовать его здесь. Держите это простым и держите это ясным; задокументируйте его и постарайтесь синхронизировать документацию и код.
Если вы хотите преобразовать данные, поступающие из пользовательской базы данных, более щадящим образом, поместите эти функции в отдельный метод преобразования и документируйте связанные функции .
В какой-то момент требования функции должны быть отмерены, четко задокументированы и выполнение должно продолжаться. «Прощение», с его точки зрения, немного немое, это дизайнерское решение, и я бы поспорил за функцию, не изменяющую аргумент. Наличие функции mutate на входе скрывает некоторую валидацию, которая потребуется клиенту. Наличие функции, которая выполняет мутацию, помогает клиенту понять это правильно.
Большой акцент здесь ясность и документ , что код делает .
источник
источник