チームで中規模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プロダクトが多数あります。枯れた技術を工夫しながら日々改善するのが長期運用のコツではないかと感じています。

builderscon 2018 に参加(登壇)してきました

数年放置していた本ブログですが、私は元気です。

builderscon 2018に参加してきました。

オープニングには間に合いませんでしたが、色々なセッションに刺激をもらいました

開発現場で役立たせるための設計原則とパターン

実況中継シリーズ 「開発現場で役立たせるための設計原則とパターン」 #builderscon 2018 - 猫型の蓄音機は 1 分間に 45 回にゃあと鳴く

設計に関しては、抽象論の空中戦になることが多い実感。「個人の感想です」が顔を出しがちになるホントこれ。設計原則に当てはめて考察するってのは筋がいい。設計コストの問題もあるにせよ、これは自身やチームのレビューに有効そうだなと実感。

Webサービスにて200週連続で新機能をリリースする舞台裏

Webサービスにて200週連続で新機能をリリースする舞台裏 / builderscon tokyo 2018 - Speaker Deck

毎週リリースとなると週刊連載を持つようなものだよなぁと思ってたけど、実際にネタのストックをためておいたりとか1話完結の漫画家ぽい

それでも毎週リリース出せるのはチームの自力があってのことだろうし、ここ数年のMackreleの開発状況を見ると尊敬せざるをえない。スタートアップ期が終わったっていうのは良い判断だし素晴らしいスピード感だったと思う (Mackerelガンガン使っております

機械学習を用いず数学でゲーム内の需要予測をする

機械学習を用いず数学でゲーム内の需要予測をする - Speaker Deck

会社の同僚のセッション。機械学習で使えるような形式やデータ量でもない場合には数式(+人間)で予測することができる。ソーシャルゲームで需要予測を行ったの実例を紹介。山場はホワイトボードで数式を書き始めたあたり、かっこいい!

Webサービスの品質とは何か?アラート地獄と監視の失敗、サービスレベル目標設計から学んだ3つの答え

Webサービスの品質とは何か?アラート地獄と監視の失敗、サービスレベル目標設計 から学んだ3つの答え - Speaker Deck

大変身につまされる思いがしました...ごめんなさい。忙しさにかまけて、ついつい放置しがちになってしまい云々....アラートがアクションにつながらないってのは本当

証券トレーディング業務におけるExcel依存を脱却するプロジェクトで直面した技術的選択とプロジェクト運営の失敗

録画撮影禁止だけのことはある、業界自体が怖いよ。ヒットマンが飛んできそうだ。 社内システムの顛末なんだけど、当初の要件としてはシステム規模が大きくならないはずなのにね。 あまり関わることのない世界だと思いたい。

ブログサービスのHTTPS化を支えたAWSで作るピタゴラスイッチ

ブログサービスのHTTPS化を支えたAWSで作るピタゴラスイッチ / The construction of large scale TLS certificates management system with AWS - Speaker Deck

そーだいなるピタゴラスイッチだ。色々悲鳴が聞こえて来てはいた(?)けどよくぞ作ったものだと尊敬する。実にはてなっぽい。

要素技術的にはDynamoDBのTTLをトリガーにするのが良さそう。ドミノを倒すトリガーについて考えていたので参考になりそう。

RDB THE Right Way ~壮大なるRDBリファクタリング物語

RDB THE Right Way - builderscon 2018/ RDB_THE_Right_Way - Speaker Deck

「データベースの寿命はアプリケーションより長い」が重い。世の10年超えのサービスはすごいよなぁ。 データと情報、技術的根拠。そして本読む時間作ろう。

ちなみに自分は以下のセッションで登壇をしてきました。

SNSでの反応を見る限りでは結構楽しめたようなので安心しました。 ここ数年ほとんど表に出ていなかったので色々緊張しました....

ソーシャルゲームが高負荷に陥っているとき、何が起こっているのか

speakerdeck.com

運営スタッフ・スポンサー・関係者の皆様、楽しいイベントありがとうございました

来年も機会があれば参加したいと思います!

APIドキュメントからモックサーバを立ち上げるWeb::API::Mockを書いた

APIドキュメント(API Blueprint)からモックサーバを立ち上げるWeb::API::Mockを書きました

Plackで作った事もあり以前紹介したapi-mockよりも、ちょっと便利になっています

APIドキュメントからモックサーバを立ち上げたい - akihitoのログ置き場

  1. モックサーバ立ち上げ時にplackupのオプションが使える
  2. 複数個のAPIドキュメントに対応
  3. 未実装のAPIリストを渡す事でステータス:501を返す

モックサーバからアプリケーションサーバへURL毎にスイッチする

3番目の仕組みを利用することで、nginxを使ってモックサーバからサーバアプリケーションに差し替える事が出来ます

upstream mock_backend {
   server 127.0.0.1:5001;
}

upstream prod_backend {
   server 127.0.0.1:5002;
}

server {

    location ~ ^/ {
         proxy_intercept_errors on;
         proxy_pass http://mock_backend;
         proxy_set_header Host $host;
    }

    error_page 501 =200 @prod;
    location @prod {
        proxy_pass http://prod_backend;
        proxy_set_header Host $host;
    }

モックサーバ(mock_backend)にnot-implemented-urlsオプションで渡したURLが501で返ってくるので、 nginx側でキャッチして、実装したサーバアプリケーションにURL毎にまわせるようになります

APIドキュメントからモックサーバを立ち上げたい

APIドキュメント(API Blueprint)を記述するとモックサーバを立ち上げてくれるサービスがあります。 GitHubAPIドキュメントを管理したり、モックサーバのアクセスログが見えたりの中々の優れ物です。

提供されるモックサーバがRESTful APIで少々融通が効かないこと、外部のWebサービスなので場合によっては採用しづらいのが難点。

ただ、API BlueprintのテストツールやモックサーバはOSSで提供されているので、サービスを使わずに利用することも可能のようです

api-mockで手軽にモックサーバを立ち上げる

公開されているモックサーバがJavaだったりして、ちょっと入れづらいなぁと思っていたら、api-mockなるモジュールがあるようですね。これもAPI Blueprintからモックサーバをたち上げてくれるようです

API Blueprint形式のAPIドキュメントを用意する

API Blueprintは、Markdownを拡張した形式です。

API Blueprint詳細

こんな感じでMethod,URI,Request,Response等を記述していきます

FORMAT: 1A
HOST: http://example

# Nopaste

タイトルと本文を投稿します

## POST /api/nopaste

+ Request

    + Header

        Host: example

    + Parameters
        + title (required, string) ... タイトル
        + body (required, string) ... 本文

+ Response 201 (text/html)

    + Header

            X-Framework: Ark

    + Body

            {
                "result": {
                    "ok": 1
                }
            }

他にも幾つかAPIを記述しておきます sample.md

API Blueprintはちょっと癖があったり未整備な所もあるのですが、現時点での要求としては十分かなと思っています。

api-mockを入れる

nodeで書かれているのでnpmを使ってインストールします

npm install -g api-mock

実行

では早速実行してみましょう

$ api-mock sample.md --port 3001
Listening on port 3001

コマンドラインから叩いて確認してみます

$ curl http://localhost:3001/api/nopaste/1234
{
    "result": {
        "title": "Hello Nopaste",
        "body": "Text"
    }
}
$ curl -I http://localhost:3001/api/nopaste/1234
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json
X-Framework: Ark
Content-Length: 83
Date: Fri, 11 Apr 2014 04:05:05 GMT
Connection: keep-alive

Headerに記述した"X-Framework: Ark"もちゃんと返ってきてますね

ドキュメントに記述した固定正常系のResponseしか返してくれませんが、それでもクライアントが サーバサイドの実装を待たずに疎通確認が出来るのはうれしいんじゃないかなと思っています

(このサンプルをApiary — Homeに持っていくとエラーになるんですが、統一感があるのでこちらの方がいいかなぁと…思っています)

手軽に多言語対応したい

YAPC::Asiaも終わったことですし(?)久々に

時間と工数が少ない中で、多言語対応する必要に迫られました。

Locale::Maketext::Lexiconあたりを使ってテンプレート側でフィルタかけて差し替えるってのが正攻法ではある

ただ、これだと

  • テンプレートを直さないとならないので、作業現場のユースケースに合っていない
  • PMやマークアップエンジニアに仕組みを周知させる時間が厳しい
  • アプリケーションの機能開発が絶賛継続中なので、余計な事はしたくない

とか諸々問題があって、考え悩んでたのですが、天啓をえました

Plack::MiddleWareを利用してみる

天啓というほどではないのですが、出口の所で全部差し替えればいいんじゃねと思いたって、 こんなモジュールを用意しました

https://gist.github.com/takihito/27d6fca91cb24be5e396

このモジュールをbuilderで以下のように読み込んで上げれば表示される HTMLタグ内の日本語が差し替わるようになる算段

builder {
    enable "Plack::Middleware::Ja2Ko";

今回は一部特定のページなので、パフォーマンスを気にしなくて良いのもあります。 Project::Ja2Ko内のTRANSLATION_LISTを別ファイル(CSV)で定義して読み込めば運用としても理解しやすいレベルになるんじゃないかと思っています

アプリケーション本体はガンガン開発してもらって、それとは関係なしに実装したほうが作業が被らない。

Plackで呼び出せるなら他のアプリケーションにも多言語フィルタかけれるんじゃないかと思った次第

追記

Plack::Middleware::Static::I18N( Plack::Middleware::I18N ? ) ってのがあるみたいですが、(放置されてるのかな) I18N宣言するモチベーションも時間ないので今回はここまで。

YAPC::Asia 2013 行ってきました

1日目は諸事情で、ほとんどのセッションを逃してしまったのですが、2日目はLTまで参加することができました。

追えていなかった技術的の話をまとめて聞けて、遅ればせながらも 最近の動向についていけるようになったかなぁと思っています。 非常に学習効率がいいですね、それだけでも価値がありました。

開発自体よりテストやDevOpsといった周辺技術の話が多かったように思います Programming AWS with Perl」「What's new in Carton & cpanm」をたてつづけに見た事もあり インフラよりの技術がプログラマーの手に届きやすい所に来ているなと実感したところです

あと、懇親会で表には出てこない各社の色々な話を聞けたのが収穫で、大変楽しかったですね。 どんなに忙しくても懇親会だけは、毎年参加するようにはしてしています

関係者の皆様、お疲れ様でした。 来年も楽しみにしております。

Monoを使ってOSXでC#

Unityを触っています

言語はJSとC#に対応しているワンソースで色々なプロットフォームに対応してくれるすぐれもので、手元ではC#で書いています

Unity上でプロジェクトをビルドして再生ってのが正当な開発方法のようですが、一旦ターミナルから手が離れてしまうこともあって少々辛いことになっています。

ターミナル上でシンタックスチェックやコンパイルした方が非常に捗るなぁと思っていたわけです。

Mono

Windows以外でも.Net Framework環境を実現するためのMonoプロジェクトがあります。 C#コンパイラが含まれていて、これを使うとターミナルからコンパイルが行えるようです。

Hello World

Hello Worldをやってみましょう

using System;
 
namespace HelloWorld
{
    class Hello 
    {
        static void Main() 
        {
            System.Console.WriteLine("Hello World!");
        }
    }
}

C#コンパイラはバージョンごとに幾つか(mcs,gmcs,dmcs)用意されています。 dmcsのバージョン4.0を使います

$ dmcs hello_world.cs

hello_world.exe ができている事を確認しmonoで実行してみましょう

$ mono hello_world.exe 
Hello World!

郵便番号住所検索

これだけだとつまらないので郵便番号から住所を検索できるプログラムを書いてみました 初心者の勉強がてらの遠回りなコードになっていますが、そこは勘弁

やっていることは

  • 郵便番号住所CSVを読み込む( http://www.post.japanpost.jp/zipcode/dl/roman.html )
  • ハッシュテーブル(Dictionary)に郵便番号をキーにして、値に住所を入れる
  • 第一引数に渡された郵便番号をキーにしてハッシュテーブルから住所を検索

これだけです。

さっそく実行してみましょう

// 複数ファイルのコンパイルは列挙すれば良い模様 
$ dmcs main.cs Zipcode.cs -out:zipcode.exe

// 郵便番号 4200838 を渡して実行
$ mono zipcode.exe 4200838
Read.search Hit !! zipcode:4200838 local:AIOICHOAOI-KU SHIZUOKA-SHI

Unityでは使えるライブラリに制限があるようですが、UIと絡まないビジネスロジックや サーバとの連携を作る際にはMonoを使って作成していくのがいいのではないかと思っています。