Привет.
В прошлый раз мы описали Has
-паттерн, обрисовали проблемы, которые он решает, и написали несколько конкретных инстансов:
instance HasDbConfig AppConfig where
getDbConfig = dbConfig
instance HasWebServerConfig AppConfig where
getWebServerConfig = webServerConfig
instance HasCronConfig AppConfig where
getCronConfig = cronConfig
Выглядит неплохо. Какие тут могут возникнуть сложности?
Ну, давайте подумаем, какие ещё инстансы нам могут понадобиться. В первую очередь конкретные типы с конфигурацией сами по себе хорошие кандидаты на (тривиальную) реализацию этих тайпклассов, что даёт нам ещё три инстанса, где каждый метод реализуется через id
, например
instance HasDbConfig DbConfig where
getDbConfig = id
Они позволяют нам легко писать отдельные тесты или вспомогательные утилиты, не зависящие от всего AppConfig
.
Это уже скучновато, но таки продолжим. Легко представить, что некоторые интеграционные тесты проверяют взаимодействие какой-то пары модулей, и мы всё ещё не хотим зависеть от конфигурации всего приложения целиком, так что теперь нам надо написать шесть инстансов (по два на тип), каждый из которых будет сводиться к fst
или snd
. Например, для DbConfig
:
instance HasDbConfig (DbConfig, b) where
getDbConfig = fst
instance HasDbConfig (a, DbConfig) where
getDbConfig = snd
Ужас. Остаётся надеяться, что нам никогда не понадобится тестировать работу трёх модулей одновременно — а то ведь придётся писать девять скучнейших инстансов. В любом случае, лично мне уже очень некомфортно, и я скорее потрачу несколько часов на автоматизацию этого дела, чем пару минут на написание десятка лишних строк кода.
Если интересно, как решить эту задачу в общем виде, причём тут зависимые типы, и как всё это в итоге будет выглядеть на хаскеле — велкам под кат.
Читать полностью »