Я хотел бы добавить кое-что еще, на что намекают другие ответы, но я не думаю, что было упомянуто явно:
@puck говорит: «До сих пор нет гарантии, что первый упомянутый аргумент в имени функции действительно является первым параметром».
@cbojar говорит: «Используйте типы вместо неоднозначных аргументов»
Проблема в том, что языки программирования не понимают имен: они просто рассматриваются как непрозрачные атомарные символы. Следовательно, как и в комментариях к коду, не обязательно существует какая-либо корреляция между тем, как называется функция, и тем, как она на самом деле работает.
Сравните assertExpectedEqualsActual(foo, bar)с некоторыми альтернативами (с этой страницы и в других местах), например:
# Putting the arguments in a labelled structure
assertEquals({expected: foo, actual: bar})
# Using a keyword arguments language feature
assertEquals(expected=foo, actual=bar)
# Giving the arguments different types, forcing us to wrap them
assertEquals(Expected(foo), Actual(bar))
# Breaking the symmetry and attaching the code to one of the arguments
bar.Should().Be(foo)
Все они имеют больше структуры, чем подробное имя, что дает языку нечто непрозрачное для взгляда. Определение и использование функции также зависит от этой структуры, поэтому она не может быть не синхронизирована с тем, что делает реализация (например, имя или комментарий).
Когда я сталкиваюсь с такой проблемой или предугадываю ее, прежде чем я в отчаянии кричу на свой компьютер, сначала я задаюсь вопросом: «Справедливо» ли вообще обвинять машину? Другими словами, было ли дано машине достаточно информации, чтобы отличить то, что я хотел, от того, что я просил?
Подобный вызов assertEqual(expected, actual)имеет такой же смысл assertEqual(actual, expected), как и для нас, поэтому нам легко их перепутать, а машине - пахать вперед и делать неправильные вещи. Если мы используем assertExpectedEqualsActualвместо этого, это может сделать нас менее вероятными, чтобы допустить ошибку, но это не дает больше информации машине (он не понимает по-английски, и выбор имени не должен влиять на семантику).
Что делает «структурированные» подходы более предпочтительными, такие как аргументы ключевых слов, помеченные поля, отдельные типы и т. Д., Так это то, что дополнительная информация также машиночитаема , поэтому мы можем заставить машину обнаруживать неправильные использования и помогать нам делать все правильно. assertEqualДело не так уж плохо, так как только проблема будет неточные сообщения. Можно привести более зловещий пример String replace(String old, String new, String content), который легко спутать с String replace(String content, String old, String new)совершенно другим значением. Простым решением было бы взять пару [old, new], которая допускала бы ошибки, которые сразу же вызывали ошибку (даже без типов).
Обратите внимание, что даже с типами мы можем не сказать машине, что мы хотим. Например, антишаблон «строковое программирование» обрабатывает все данные как строки, что позволяет легко перепутать аргументы (как в этом случае), забыть выполнить какой-то шаг (например, экранирование), случайно сломать инварианты (например, создание непонятного JSON) и т. д.
Это также связано с «булевой слепотой», когда мы вычисляем группу булевых значений (или чисел и т. Д.) В одной части кода, но при попытке использовать их в другой неясно, что они на самом деле представляют, мы их перепутали и т. д. Сравните это, например, с различными перечислениями, которые имеют описательные имена (например, LOGGING_DISABLEDа не false) и которые вызывают сообщение об ошибке, если мы их перепутали.