Хорошо, я не пытаюсь запустить войну пламени здесь, и я знаю, что спор между статическими и динамическими языками много раз долго обсуждался, включая здесь. Но у меня есть очень практический вопрос, на который, надо надеяться, кто-то здесь может пролить некоторый свет. Извините за длину, но это не простой вопрос с, вероятно, не простой ответ.
Ruby, PHP и JavaScript являются довольно популярными языками в эти дни, и у них есть много людей, которые защищают их и утверждают, что быть с динамическим контролем типов не сдерживает разработчика. Я плохо знаком с этими языками и хотел бы начать использовать их для больших проектов, но здесь являюсь основным сценарием рефакторинга, который подходит все время на работе (работа == C#), и я задаюсь вопросом, чем подход был бы в Ruby - я выбрал Ruby, потому что это - OO.
Хорошо, я использую Ruby, и я создаю Клиентский объект. Это имеет методы для загрузки/сохранения/удаления от базы данных. Это хорошо, и люди используют его. Я добавляю больше методов для других вещей, и люди используют его больше. Я добавляю метод для вычисления истории заказов на основе некоторых параметров. К настоящему времени этот класс используется на всем протяжении системы. Затем однажды я решаю изменить параметры на методе GetOrderHistory. Так я:
Но теперь что? У меня есть dozens/hundreds/whoknows, сколько других мест в системе, которая должна быть изменена. На динамическом языке OO как Ruby или JavaScript, как я пошел бы об этом?
Первое, что пришло на ум, не зная Ruby очень хорошо, я могу думать о двух немых ответах:
Так существует ли хороший ответ на это? Кажется, что IDE пришлось бы нелегко. Если у меня был код такой как
c = Customer.new
это смогло бы понять это, но что, если это
c= SomeFunctionThatProbablyReturnsACustomerButMightReturnOtherThings()
Таким образом, какой подход был бы Вы, эксперты Ruby берут в этом случае?
Один из веских аргументов, который вы услышите, - это то, что вам следует заранее писать тесты. Теоретически это покажет вам, где именно нужно изменить приложение, если что-то еще изменится.
Но это только верхушка айсберга. Ruby разработан с учетом определенных рекомендаций, таких как короткие выразительные функции, разделение ответственности на модули, неповторение кода (DRY), принцип наименьшего удивления и т. Д .; плюс набор рекомендуемых практик, таких как сначала тестирование, передача параметров в виде хеш-параметров, разумное использование метапрограммирования и т. д. Я уверен, что другие динамические языки тоже делают это.
Если c
не является Клиентом, то, по крайней мере, я ожидаю, что будет действовать как клиент. IDE могут искать утиную типизацию, что более гибко, чем проверка экземпляра определенного класса.
Некоторые IDE (по крайней мере, Rubymine) также обращаются к соглашениям. Например, в приложениях Rails Rubymine переходит к файлу схемы и добавляет свойства модели в базу данных как методы. Он также распознает ассоциации (has_many, own_to и т. Д.) И динамически добавляет соответствующие методы, которые Rails генерирует под капотом.
Теперь это в значительной степени снижает потребность в рефакторинге, по крайней мере, сводит его к минимуму. Но, конечно, не решает . И я не думаю, что это можно решить.
Вероятно, это будет не лучший ответ на ваш вопрос, но я предпочитаю разрабатывать методы, принимающие хэш для покрытия будущих изменений.
Пример:
def my_method(options = {})
if options[:name]
...
end
end
Я думаю, что многие более продвинутые специалисты по Ruby захотят реализовать какой-то шаблон метапрограммирования.
Другие варианты могут включать в себя переопределение метода в подклассе для выполнения желаемых функций.
Или, как насчет ...
def get_order_history(required_param, options = [])
@required_param = required_param
if options[:do_something_else]
result = other_method(options[:do_something_else])
else
result = ...
end
result
end
def other_method(something_else)
...
end