В началье статьи хочу сразу заметить, что я не претендую на новизну, а только хочу поделиться/напомнить о такой возможности как IoC DI. Также у меня почти нет опыта написания статей, это моя первая. Я старался как мог, если что не судите строго.  Большая часть проектов на Rails, с которыми я сталкивался, имеют одну большую проблему. Они либо не имеют тестов вовсе, либо их тесты проверяют какую-то незначительную часть, при этом качество этих тестов оставляет желать лучшего. Основная причина этого заключается в том, что разработчик просто не знает как можно написать код так, что бы в unit-тестах тестировать только написанный им код, а не тестировать код, который, допустим, содержится в каком-то ином сервисном объекте или библиотеке. Далее в голове программиста складывается логичная цепочка, а зачем мне вообще выносить код бизнес логики в другой слой, я же тут всего пару строк добавлю и все будет соответствовать требованиям заказчика. И это очень плохо, потому что модульное тестирование теряет устойчивость к рефакторингу, управлять изменениями в таком коде становится тяжело. Энтропия постепенно растет. А если вы уже боитесь рефакторить свой код, дела очень плохи. Для решения в подобных задач в мире Java уже давно существует ряд библиотек и нет особого смысла изобретать велосипед, хотя, надо заметить, что эти решения весьма громоздкие и не всегда есть причина их использовать. Рубисты видимо как-то иначе решают подобные задачи, но я, честно говоря, так и не понял как. По этому я решил поделиться как это решил сделать я. Основная идея заключается в том, что для объектов имеющими зависимости мы должны иметь возможность управлять ими. Рассмотрим пример: Чтобы протестить метод block_user мы попадаем на неприятный момент, ведь y нас сработает notify из NotificationService и мы вынужденны обрабатывать какую-то минимальную часть, которую выполняет этот метод.
Инверсия позволяет нам просто выйти из такой ситуации если мы реализуем UserService, например, так: Теперь при тестировании мы подаем в качестве NotificationService mock объект, и проверяем, что block_user дергает методы notification_service в правильном порядке и с правильными аргументами. Когда сервисных объектов в системе становится много, конструировать самому все зависимости становится трудно, код начинает обрастать лишними строками кода, которые снижают читаемость. В связи с этим пришла в голову написать небольшой модуль, который автоматизирует управление зависимостями. Тут есть один нюанс, сервис должен быть Singleton, т.е. иметь метод instance. Проще всего сделать это написав include Singleton в сервисном классе. Теперь в ApplicationController добавим И теперь в контроллерах можем делать так В спеке этого контроллера мы автоматом получим instance_double(WelcomeService) в качестве зависисомости. Представим, например, что в нашей системе есть несколько вариантов как мы можем отправлять уведомления, например ночью это будет один провайдер, а днем другой. При этом провайдеры имеют совершенно разные протоколы отправки. В целом интерфейс NotificationService остается тем же, но есть две конкретные имплементации. Теперь мы можем написать класс, который будет выполнять условный маппинг сервисов Теперь когда мы берем инстанцию сервиса в Services::Helpers::Service.instance мы должны проверить есть ли *Mapper объект, и если есть, то взять константу класса через take. Разработчик