Tagged: feature flag

[Grails] Избегайте использования Environment вне файлов конфигураций

Внутри Grails есть великолепный механизм для условного выполнения кода в зависимости от текущей среды (Environment).
Например внутри DataSource.groovy можно указывать различные настройки базы данных:

// environment specific settings
environments {
    development {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }
    }
    production {
        dataSource {
            dbCreate = "update"
            url = "jdbc:h2:prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }
    }
}

Наверняка у вас почти в каждом файле конфигурации есть настройки под среду.

Но очень часто я натыкался на то что класс Environment.current начинает использоваться внутри контроллеров, вьюх и сервисов. А стандартный тег if и вовсе имеет атрибут для проверки текущего окружения:

<g:if env="test"> ... </g:if>

Я постепенно пришёл к тому что этого следует избегать, потому что теряется читаемость и гибкость. Вместо этого лучше явно создать опцию в Config.groovy, включать или выключать её в зависимости от среды а и потом проверять её. Вот например что делает этот код?

    <g:if env="test">
        <meta name="controller" content="${controllerName}"/>
        <meta name="action" content="${actionName}"/>
    </g:if>

На самом деле этот код добавляет имя контроллера и экшена которые отрисовли страницу и они потом проверяются функциональным тестом. Это это бывает очень удобно для дебага.
А теперь давайте мы создадим в файле Config.groovy опцию

environments {
    development {
        com.example.showActionNameInPageMeta = true
    }
    test {
        com.example.showActionNameInPageMeta = true
    }
    production {
        com.example.showActionNameInPageMeta = false
    }
}

и теперь

    <g:if test="${grailsApplication.config.com.example.showActionNameInPageMeta}">
        <meta name="controller" content="${controllerName}"/>
        <meta name="action" content="${actionName}"/>
    </g:if>

В результате эта опция улучшила читаемость кода. Кроме того теперь мы всегда можем добавить новое окружение, например testFunctional для функциональных тестов и внутри включить нашу опцию, при этом не переписывая код.
И что особенно важно, что в случае каких то проблем в продакшене сисадмин может поменять конфигурацию и перезапустить сервер не перекомпилируя приложение.
Кроме того, все такие опции теперь не размазаны по коду а лежат в одном месте где их все можно посмотреть.

В более широком смысле такой подход называется Feature flag, и его активно используют например в Amazon.