Przejdź do treści

Implementacja

Sposób implementacji Feature Flag w systemie zależeć będzie od tego, jak ma być uruchamiana nasza aplikacja i jak dużą kontrolę chcemy mieć nad flagami w czasie rzeczywistym.

Flagi zahardcodowane w aplikacji

Możemy zapisać stan flag w kodzie naszej aplikacji, czy to commit'ując odpowiedni plik do repozytorium, czy generując go podczas procesu budowania.

flags.php
<?php
return array(
    'show_hello_world' => false
);
FeatureFlagsInterface.php
<?php
interface FeatureFlagsInterface
{
    public function setEnabled(string $flag, bool $enabled = true) : void;
    public function isEnabled(string $flag) : bool;
}
InMemoryFeatureFlags.php
<?php
class InMemoryFeatureFlags implements FeatureFlagsInterface
{
    private $flags = [];

    public function __construct(array $flags = []){
        $this->flags = $flags;
    }

    public function setEnabled(string $flag, bool $enabled = true) : void
    {
        $this->flags[$flag] = $enabled;
    }

    public function isEnabled(string $flag) : bool
    {
        return isset($this->flags[$flag]) ? $this->flags[$flag] : false;
    }
}
index.php
<?php
// assume configured autoloader

$input = require "flags.php";
$flags = new InMemoryFeatureFlags($input);

Przy takiej implementacji, zmiana stanu flagi będzie wymagała od nas modyfikacji pliku w repozytorium lub co najmniej przebudowania aplikacji i wdrożenia nowej wersji.

Argumenty wiersza poleceń

Jeśli uruchamiamy aplikację z linii poleceń (cli), możemy parsować argumenty przekazane podczas uruchomienia naszej aplikacji i z ich pomocą ustawić początkowy stan flag.

<?php
$flags = new InMemoryFeatureFlags();
if(in_array($argv, '--show-hello-world'){
    $flags->setEnabled("show_hello_world");
}
flags = new InMemoryFeatureFlags(); 
if(args.contains("--show-hello-world")){
  flags.setEnabled("show_hello_world");  
}

Taka implementacja sprawi, że do zmiany stanu flagi wystarczy uruchomić aplikację ponownie, podając przy jej uruchomieniu inne parametry. Przy małej skali może to być całkiem wygodne rozwiązanie.

Wartości flag w zmiennych środowiskowych

Uniwersalnym sposobem kontrolowania zachowania aplikacji jest stosowanie odpowiednich zmiennych środowiskowych.

Podobnie jak w przypadku parametrów wywołania, zmienne środowiskowe wpływają na naszą aplikację raz, podczas jej urchomienia.

EnvOverrider.php
<?php
class EnvOverrider
{
    public function overrideFlags(array $flags) : array
    {
        foreach($flags as $flag => $value){
            $env = getenv("FEATURE_FLAG_".strtoupper($flag));
            if($env !== false){
                $flags[$flag] = (bool)$env;
            }
        }
        return $flags;
    }
}
index.php
<?php
// assume configured autoloader

$input = require "flags.php";
$envOverrider = new EnvOverrider();
$flags = new InMemoryFeatureFlags($envOverrider->overrideFlags($input));

Zewnętrzna baza danych

Możemy też użyć zewnętrznego storage'u (jak baza danych SQL lub usługa no-SQL) i pobrać stan flag podczas przetwarzania request'u do naszej aplikacji.

Taka strategia pozwoli nam na zmianę stanu flag bez konieczności restartu usługi, ale może powodować dodatkowy narzut wydajnościowy.

Mikroserwis zarządzający flagami

Możemy też odpytać zewnętrzną usługę i pobrać stan flag. Jednym z darmowych narzędzi tego typu jest Unleash.

Takie rozwiązanie jest najwygodniejsze z punktu widzenia biznesu, bo nie wymaga zaangażowania osoby technicznej, a wszystkich zmian dokonujemy z wygodnego interfejsu.

Należy jednak pamiętać, że zastosowanie dodatkowej usługi wpływa na wydajność aplikacji, a awaria osobnego mikroserwisu może przyczynić się do niestabilności naszej aplikacji.