第9章 新しい機能を追加する(その1)

前回までで一通りの機能の切り離しはおわりました。 実際にアプリを運用段階になると本番公開環境と開発環境と、のように 実行環境を分けたいことがあります。 そういう時のためにアプリケーション用の設定ファイルを用意しておくと便利です。

9.1 設定ファイルを導入

今回は公開環境、開発環境、テストコード環境の3つということにします。

9.1.1 設定ファイルの種類を考える

設定について

  • 下記のような名前で環境ごとの条件を設定
    • 公開環境 -> `production`
    • 開発環境 -> `development`
    • テストコード環境 -> `testing`

例として今回は下記のようなファイル構成としたい

beginning_mojo        # Application directory
...
|- etc                # 設定ファイル
|  +- beginning_mojo.common.conf        # 共通設定ファイル
|  +- beginning_mojo.development.conf   # 開発環境の設定ファイル
|  +- beginning_mojo.production.conf    # 公開環境の設定ファイル
|  +- beginning_mojo.testing.conf       # テストコード環境の設定ファイル
...

9.1.2 設定ファイルを用意する

下記のような内容のファイルを作成

% touch etc/beginning_mojo.common.conf
% touch etc/beginning_mojo.development.conf
% touch etc/beginning_mojo.production.conf
% touch etc/beginning_mojo.testing.conf

設定ファイルは Perl のハッシュ形式で記述

etc/beginning_mojo.common.conf

+{
    schema_file => app->home->child('db', 'bulletin.sql')->to_string,
    db_file     => app->home->child('db', 'bulletin.db')->to_string,
    mode        => app->mode,
};

etc/beginning_mojo.development.conf

+{};

etc/beginning_mojo.production.conf

+{};

etc/beginning_mojo.testing.conf

+{
    db_file => app->home->child('db', 'bulletin.testing.db')->to_string,
};

9.1.3 アプリケーションに設定する

設定ファイルを読み込むための調整をしていきます。

lib/BeginningMojo.pm

# ...

sub startup {
    my $self    = shift;
    my $mode    = $self->mode;
    my $moniker = $self->moniker;
    my $home    = $self->home;
    my $common  = $home->child( 'etc', "$moniker.common.conf" )->to_string;
    my $conf    = $home->child( 'etc', "$moniker.$mode.conf" )->to_string;

    # 設定ファイル (読み込む順番に注意)
    $self->plugin( Config => +{ file => $common } );
    $self->plugin( Config => +{ file => $conf } );
    my $config = $self->config;

    $self->helper(
        model => sub { BeginningMojo::Model->new( conf => $config ); } );
    $self->helper(
        teng => sub { BeginningMojo::Model->new( conf => $config )->teng; } );
    # ...
}

1;

lib/BeginningMojo/Model.pm

# ...
has bulletin =>
    sub { BeginningMojo::Model::Bulletin->new( conf => shift->conf ); };
# ...

設定ファイルの読み込みに変更

lib/Test/Mojo/Role/Basic.pm

# ...
sub init_db {
    my $self = shift;

    # データベースの初期化間違いを防止
    die 'not mode testing!' if $self->app->config->{mode} ne 'testing';

    my $db     = $self->app->config->{db_file};
    my $schema = $self->app->config->{schema_file};

    # ...
}
# ...

lib/BeginningMojo/Model/Base.pm

# ...

has [qw{req_params conf}];

# 全てのモデルで共通して使えるメソッドを定義
sub teng {
    my $self    = shift;
    my $dsn_str = 'dbi:SQLite:' . $self->conf->{db_file};
    my $user    = '';
    my $pass    = '';
    my $option  = +{
        RaiseError     => 1,
        PrintError     => 0,
        AutoCommit     => 1,
        sqlite_unicode => 1,
    };
    # ...
}

1;

テストコードを実行、エラーが出ることに注意

% docker-compose exec web carton exec -- prove --lib
t/bulletin.t .. not mode testing! at /Users/yk/github/sakura_developers/beginning_mojo/lib/Test/Mojo/Role/Basic.pm line 20.
...

9.1.4 環境変数の設定について

MODE については下記のような挙動になっている

  • MODEについての注意
    • `app->mode`メソッドは環境変数`MOJO_MODE`で判定している
    • アプリケーションの実行
      • morbo コマンドは標準で`development`で実行している
      • 実行コマンド実行時に任意に環境変数`MOJO_MODE`に指定すると変更になる
    • テストコードの実行
      • prove コマンドで実行するのはテストコード
      • テストコード内でアプリのスクリプトを読み込む前に環境変数`MOJO_MODE`に指定すると変更になる
今回は docker 経由でのアプリケーションの起動になっているので docker の設定も一工夫必要になる

docker-compose.yml

...
    environment:
      MOJO_MODE: '${MOJO_MODE-}'
    command: '${BULLETIN_COMMNAD_FILE-./bin/compose-cmd.bash}'
...

docker-compose 起動時に読み込む環境設定ファイルを用意

% touch etc/.env.development
% touch etc/.env.production

etc/.env.test

BULLETIN_COMMNAD_FILE="./bin/compose-cmd-test.bash"
MOJO_MODE="testing"

etc/.env.development

MOJO_MODE="development"

etc/.env.production

MOJO_MODE="production"

ここまできてテストコードを起動するときの方法がふたつになる

(テストコード実行、アプリケーションが実行されている状態で別のウインドウから)
% docker-compose exec --env MOJO_MODE=testing web carton exec -- prove --lib

(テストコード実行、アプリケーションが実行されていない状態で)
% docker-compose --env-file ./etc/.env.test up

以降はテストコード実行時にモード指定するので修正

lib/Test/Mojo/Role/Basic.pm

# ...
sub init {
    my $self = shift;

    # テストコード実行の制限
    die 'not mode testing!' if $self->app->config->{mode} ne 'testing';

    $self->init_db;
    return;
}
# ...

9.1.5 まとめ

9.1.6 次回

今回は環境設定まわりをととのえました。

次回はデータベースロジックを拡張するやり方をやってみたいと思います。