チームで中規模Perlアプリケーションを開発する工夫

Perl Advent Calendar 2018 13 日目の記事です。

チームで開発を行うとき、機能単位で担当者を割り振り、実装することが多いかと思います。

しかし、実際には一人で実装するにはボリュームが大きく、機能も分割しにくいケースがよくあります。

このような時には、ビジネスロジックをプラガブルに設計しておくことで、開発のスケールアウトをしやすくなります。

プラグインの実装

複数の処理を繋ぎ合わせ、次処理に回すような流れを想定した場合、菱形多重継承のような実装モデルが想像されます。

各クラスで実装した処理をメソッド順序解決を行いながら順次実行されるわけです。

f:id:t-akihito:20181212161145p:plain
多重継承 Class A → B → C → Dの順に init が実行される

このようなプラガブルな構造を実装する方法としては、古くはClass::C3のようなモジュールがありました。

しかし、次処理にまわしたい要件を実現することに、多重継承を用いて解決することには牛刀感があります。

合成の利用

MooseにはRoleという仕組みがあり、これを使うことでモジュールへの合成を行うことができます。

呼び出し元にプラグインを追加して行くことにより機能を追加していくことになります。

処理をクラス毎に分割し実装担当者が メソッドの in -out のチェックを行うようにすれば、個々人が並列に実装作業を行うことができるようになります。

package Yyy;
use Mouse::Role;

before 'init' => sub {
    my $self = shift;
    push @{$self->list}, 'y';
};

1;

package Zzz;
use Mouse::Role;

before 'init' => sub {
    my $self = shift;
    push @{$self->list}, 'z';
};
1;

package Main;
use Mouse;
with ' 'Yyy', 'Zzz';

has list => (
    is      => 'rw',
    isa     => 'ArrayRef',
    default => sub { []; }
);

sub init {
    my $self = shift;
    my $string = join ('-', @{$self->list});
    return $string;
}
1;
use Main;
my $m = Main->new();
print $m->init(); # 呼び出し順をたどって z-y が出力される

with に追記した逆順に各クラスの before 'init' が実行処理されるようになっています。上記のコードの場合は Yyy, Zzzのそれぞれのクラスを担当者で実装してもらうわけです。

道具の進歩(github)により開発が衝突する機会が少なくなってきてはいますが、それでも時には人的リソースのスケールアウトが可能なように設計をしておくことも一つの案だと思っています。

現場では依然として活発に稼働しているPerlプロダクトが多数あります。枯れた技術を工夫しながら日々改善するのが長期運用のコツではないかと感じています。