はじめに
手続き型プログラミング言語に、部分的に宣言型プログラミングの要素を入れることで、ある種の非常に複雑な処理を単純に実装することができるようになります。
今回はその話を書きます。
例として上げておくと、ウェブページの複雑なバリデーション処理や、
CSVやExcelの生成、インポート処理などが挙げられます。
この記事でいうところの「宣言的プログラミング」というのは自称で、「宣言型プログラミング言語」の本来の用語とはやや異なります。
宣言型プログラミング言語についてご興味の方は他の記事をご覧ください。
手続き型に書くのが向かない例
例えば、商品リストをExcelとして0から生成することを考えましょう。
全体が縦横の数値表になっているとして、カラムがたくさんあるケース。
仮に30カラムぐらいあったとします。(m=30)
- 商品名
- 商品コード
- 原価
- 販売価格
- メーカー型番
- etc..
各セルにはいくつもの属性があり、個別に設定する必要があります。
- 元データから取ってくるフィールド名や計算方法
- 値の型(文字列、整数、実数など)
- 文字のフォント、サイズ、ボールド、イタリックなど
- 文字色や背景色
- 罫線やセルの連結など
仮に10属性ぐらいあったとします(n=10)
それぞれの処理をモジュール化などして1行で書けるようにしたとしても、それでも長すぎるプログラムになってしまいます。
これらの属性がn個あるとして、mカラムある表を出力するには
1行処理するごとにm*n行のコードを書くことになります。
(例でいうと 30*10 = 3000)
表題、表の項目部分、表のデータ部分と処理が分けられているならば
これらを3パターン書くことになるでしょうか。
3*m*nですか? うんざりしてきました。
処理手順をデータとして宣言する
そこで、処理そのものをいったんデータとして表現します。
ここでは仮にPHPで実装していたとしましょう。
$columnList = [
['caption' => '商品名', 'type' => 'string', 'field' => 'productName', 'font' => 'normal', 'lines' => 'under'],
['caption' => '商品コード', 'type' => 'jan11', 'field' => 'productCode', 'font' => 'bold', 'lines' => 'under'],
['caption' => '原価', 'type' => 'decimal', 'field' => 'cost', 'font' => 'normal', 'lines' => 'under'],
['caption' => '販売価格', 'type' => 'decimal', 'field' => 'price', 'font' => 'normal', 'lines' => 'under'],
['caption' => 'メーカー型番', 'type' => 'alphanumeric', 'field' => 'makerCode', 'font' => 'normal', 'lines' => 'under'],
/// etc..
];
このような感じで、出力したいカラムのリストを配列で表現してしまいます。
するとn属性あった処理内容が1行になり、全体でm行程度に収まるわけです。
あとは実際の処理を書いていくだけです。
/** Excelデータを生成する本体 */
function generateProductExcel(PhpSpreadsheet $sheet, array $products)
{
foreach($products as $product) {
foreach($columnList as $column) {
$field = $column['field'];
generateColumn($sheet, $product->{$field}, $column);
}
}
}
/** Excelのカラム1個分を生成する */
function generateColumn(PhpSpreadsheet $sheet, $value, array $column)
{
// 省略。ここにn個の属性分の処理内容を書く
}
つまり、全体でm*n個必要だった処理が、m+n個に分解されたわけです。
カラム数や属性数が多いケースだと劇的にコード量が減ります。
実装する言語はPHPに限らずどんな言語でも使えるので応用が効きます。
また、宣言部分は表データに非常に近い形式なので、JSON、CSV、YAMLなどでテキストデータとして外部化してもいいですし、
マスタテーブルに直接入れてしまっても良いでしょう。
以上です。