本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはうたがわききさんで、テーマは「他言語のライブラリをPerlに移植する」です。
本稿は、執筆時点2021年5月の最新版であるPerl 5.34.0を用いました。本稿のサンプルコードは、WEB+DB PRESS Vol.123のサポートサイト から入手できます。
なぜ他言語のライブラリをPerlに移植するのか
筆者は、Twitterに投稿する文章を整形・検証するためのtwitter-text ライブラリをPerl に移植した、Twitter::Text を実装・公開しました。本稿では、Perl以外のプログラミング言語で実装されているライブラリをPerlに移植する際の考え方や気を付けるべきことについて、Twitter::Textを例に解説します。
はじめに、他言語で実装されたライブラリをPerlに移植する理由を述べます。
使いたいライブラリのPerl実装があるとは限らない
サービスのSDK(Software Development Kit )のように、あるライブラリが提供する機能をPerlから使いたいが、使いたいライブラリにPerlでの実装が用意されていないことがしばしばあります。対象のライブラリをPerlに移植することで、ライブラリの機能をPerlから使えるようになります。
ランタイムをPerlで完結させることができる
他言語で実装されたライブラリをPerlに移植してから使うことで、複数の言語処理系をメンテナンスする必要がなくなります。一般に、管理する言語処理系の数が多くなればなるほど、次のようなタスクを言語処理系ごとに行う必要が出てくるので、管理コストが高くなります。
処理系自体のバージョンアップ
使っているライブラリのアップデート
脆弱性対応
ランタイムをPerlで完結させることで、これらの管理コストを低減させることができます。
コマンドラインラッパとして実装する場合との比較
ライブラリをPerlに移植する方法のほかにも、ライブラリが提供する機能を利用するためのコマンドラインラッパを書くことで、ライブラリが提供する機能をPerlからも使えるようになるかもしれません。
コマンドラインラッパを実装する方法はわかりやすいですが、プロセスを起動する分のオーバーヘッドが発生します。また、ライブラリの実装言語によっては、Perlとは別の言語処理系を用意する必要があって管理コストが増大します。さらに、ユーザー入力をコマンドライン引数として渡す際に注意深くエスケープしないと、コマンドインジェクションなどの脆弱性を埋め込んでしまう危険性があります。
Web APIとして実装する場合との比較
もう一つ考えられる方法として、ライブラリが提供する機能を利用するためのWeb APIを実装する方法が考えられます。
この方法でも、HTTP通信のオーバーヘッドや、別の言語処理系を用意するコストからは逃れられません。また、ライブラリの機能を使う頻度が高すぎると、HTTP通信を受けるコンポーネントがダウンするかもしれません。ライブラリを使う側の実装を注意深く行わないと、ダウンしたコンポーネントに巻き込まれて本体のアプリケーションでも障害が発生します。
実装への理解を深められる
他言語のライブラリをPerlで実装しなおすことで、ライブラリ自体の実装やPerlのエコシステムへの理解を深めることができます。
普段ライブラリを使っているときは、ライブラリの内部実装についてはあまり意識することがないかもしれません。筆者はライブラリを移植することで、それまでブラックボックスのように見えていたライブラリの実装方法についての理解を深められました。
また、他言語のライブラリをPerlに移植するためには、言語ごとの機能差やPerlでの実現方法について考える必要があります。筆者はライブラリを移植することで、Perlでの文字列処理の方法、テストの書き方、移植を実現するのに必要なCPANモジュールなど、Perlの言語機能やエコシステムについての理解を深めることができました。
Perlのエコシステムに貢献できる
他言語のライブラリをPerlで移植しなおすことによって、それまでPerlだけでは使うことが難しかったライブラリの機能をPerlでも使うことができます。移植したライブラリをCPANに公開することで、ライブラリを使いたかったほかの人にもライブラリの機能を提供できます。
移植方針の決定
他言語のライブラリのPerlへの移植は一見簡単そうに感じますが、気を付けるべきポイントがいくつかあります。また、漠然と移植作業を行うと、移植完了の見通しが立たずモチベーションが低下してしまうかもしれません。
本節では、Twitter::Textを例に、Perlへの移植方針の決定方法を解説します。
移植元ライブラリのドキュメントの調査
まずは自分が何を移植しようとしているのかを把握することが大事です。ライブラリが提供している公式のドキュメントをしっかり読み込みましょう。
また、ライブラリが準拠している仕様書や解説文書が公開されているのであれば、それもしっかり読みましょう。筆者がtwitter-textを移植する際は、Twitter APIにおける文字数カウントの方法を解説した文書 を読んでからライブラリの移植に取りかかりました。
ライブラリの移植元実装の選定
移植元の言語と移植先の言語が似ているほど、移植がしやすくなります。したがって、ライブラリが複数の言語で実装されている場合、できるだけPerlに似たパラダイムや文法を持つ言語を参考に移植しましょう。
移植元のライブラリがPerlに似た言語で実装されていない場合は、処理がどのような流れで実装されているかを把握することが重要です。
Twitter::Textの移植元のライブラリであるtwittertextには、Java、Ruby、JavaScriptなどいくつかの実装が用意されています。このうちRubyはPerlと共通点を多く持つプログラミング言語ですので、Ruby実装をもとにすることにしました。
移植する機能の優先度付け
twitter-textには、ツイートのバリデーションのほかにもさまざまな機能が用意されています。ライブラリを移植するにあたっては、すべての機能を移植できるのが最も望ましいでしょう。一方で、それらの機能をすべてPerlで実装しなおすのは時間がかかります。
筆者は、twitter-textが持つ機能のうち、ツイートのバリデーションを行うのに必要な機能の実装から取りかかりました。バリデーションに関係ない機能は優先度を下げ、余裕があれば実装することにしました。
ゴールの明確化
移植先のライブラリでも、移植元と同様のテストケースにパスすることを確かめましょう。ユニットテストを書いて、テストが失敗する箇所を順に修正しながら実装していくのがやりやすいと思います。ユニットテストは移植のみならずリファクタリングやバグ修正の助けにもなるので、書いて損はありません。
twitter-textの場合は、テストケースがYAML(YAML Ain't Markup Language )形式で提供されていたので、それらのテストケースにパスすることを目標として実装を進めました。
対象バージョンの決定
Perlは後方互換性を大事にする言語です。ライブラリを作る際にも、できるだけ多くのバージョンのPerlで使えるように実装しましょう。
CPANにアップロードされた多くのライブラリは、Perl 5.10以降で動作することを目標に実装されています。したがって、ライブラリを移植するにあたってもPerl 5.10以降をターゲットとして実装することが望ましいでしょう。
Perl::MinimumVersion モジュールに含まれるperlver
コマンドを使うと、静的解析をもとにライブラリを使うことができる最小のPerlのバージョンを推定できます。以下に、Twitter::Textのlib
ディレクトリ以下のファイルをperlver
コマンドで解析した結果を示します。
% perlver --blame lib
------------------------------------------------------
File : lib/Twitter/Text.pm
Line : 124
Char : 21
Rule : _regex
Version : 5.009005
------------------------------------------------------
/($Twitter::Text::Regexp::valid_hashtag)/gp
------------------------------------------------------
正規表現リテラル(_regex
)が原因で、ライブラリを動かすにはPerl 5.9.5以上が必要である、と推定されていることがわかります。このように推定されたのは、Perl 5.9.5で追加された正規表現リテラルのp
修飾子を使っているためです。
このようにperlver
コマンドで検出した古いバージョンとの互換性がない構文を、より小さなバージョンのPerlでも解釈できる等価な構文に書き換えていくことで、ライブラリのPerlバージョンの後方互換性を保つことができます。
また、ライブラリをCPANにリリースしたあとはCPAN Testers Report を確認することも重要です。CPAN Testers Reportでライブラリのインストールに失敗したレポートが届いていたら、その内容を確認してどのように対処するかを考えましょう。CPAN Testers Reportには、インストールに失敗した環境の情報やテストのログ出力などが含まれているので、それらがデバッグの鍵になります。
ライブラリが古いバージョンのPerlでは使えないことがわかっていて、修正対応が難しい場合は、使える最小のPerlのバージョンを明示的に指定しておきましょう。Minilla を使ってライブラリを開発する場合は、cpanfileにrequires 'perl', '5.010000'
のように記述することで、必要なPerlの最小バージョンを指定できます。Minillaについての詳細は、本連載の第50回「Minillaを使ったモダンなCPANモジュール開発 」を参照してください。
<続きの(2)はこちら 。>
特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現!
特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう
特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT