
2025.02.12
職員一人あたり52時間の残業削減に成功 kintone導入がもたらした富士吉田市の自治体DX“変革”ハウツー
怠惰なエンジニアのためのコード生成(全1記事)
リンクをコピー
記事をブックマーク
高橋一平氏(以下、高橋):では、怠惰なエンジニアのためのコード生成ということで、リクルートマーケティングパートナーズの高橋が発表させていただきます。
さっそくですが、みなさんコードを書くのは好きでしょうか? 僕はあんまり好きではありません。コードを書いていて、ロジックを書くのはおもしろいですが、ボイラープレートや定型文的なコードなどをどうしても書かなければならないことは多いと思います。
こうしたボイラープレートを何度も書くのはしんどい。共通化、設計とかで解決しようとしても限界があるということで、コード生成をして解決しようというのが今回のお話です。
本発表でお話することですが、直接的なコード生成の話。ソースコードをファイルで書き出すという話と、マクロなどを使ったメタプログラミングによって先ほどの問題を解決しようという2つのお話をさせていただきます。
まず、コード生成をするにあたっての前提条件ですが、きちんと設計がなされている、クラスや関数の役割が明確になっていることが前提となってきます。
ルールがないような煩雑なめちゃくちゃなものに関してはコード生成することはできません。それに加えて、副作用がなかったりだとかDIをしっかり使っていたりだとか、テストのしやすいプログラミングになっていることが、まずコード生成よりも先にやらなければならないことだと考えています。
さっそく、コード生成の具体的な方法について話していきます。まずはパーサを書きましょうということなんですが、パーサというのは、構造化されている対象に対してだったら必ず書けます。
例えばXMLであったり、JSONであったり、Protocol Buffersだったり、SQLであったり、はたまた誰かが作ったExcelのフォーマットだったりとか、いろいろあると思いますが、構造化されていれば必ずパースはできる。
開発言語にも依存しない方法なので汎用的にも使えます。例えばSwiftで開発してます、だけどパーサはHaskellで書いてみてSwiftのコードを生成しますとか。そういう使い方でもいいと。けっこう汎用性の効く方法なので、困ったらパーサを書こうということですね。
パーサを使った具体的なコード生成の方法について説明していきます。スキーマ情報を利用したコードの生成の方法ですね。
まずスキーマをまるごとダンプして、それをプログラムで扱いやすいかたちへパースする。
このときにSQLの構文すべてを網羅したようなパースを書かなければならないわけではなくて、ダンプしたものがどういったかたちになるのかに基づいて、ある程度限定したかたちでパースを書いて作るくらいで十分だと思います。
そのパースしたものからDAO関連のソースコードを生成できます。例えばデータモデルやDAO、あとDAOのテストコード、またデータモデルのファクトリなど。そういったものに関してスキーマの情報をもとに自動生成することができて、実際に我々のサービスでもこういったことをやっています。
続いてメタプログラミングについてです。メタプログラミングというのはプログラムを扱うようなプログラミング手法のことで、プログラムを入力したり出力したりするようなプログラミング手法のことです。
メタプログラミングをすることによってなにが嬉しいかと言うと、構文木だとか型の情報にアクセスすることができます。ということはメタプログラミングを利用することで、利用しないようなプログラミングと比べてプログラムの表現力が高まるということが挙げられます。
具体的にメタプログラミングを使ってどういったことができるのかをみていきたいと思います。我々のプロダクトでもこういうことをやっているんですけれども、テストコードのテンプレートの生成です。
ユースケースだとかそういったもののテストのコードの生成だと考えてもらえればいいんですが、例えばテストしたい対象のコードを文字列として読み込む。そこからマクロなどを使って構文木の情報を持ってくる。
そうすると何ができるかと言うと、パースされた構文木の情報がわかるので、モックすべき関数がどんなものかがわかる。モックすべき関数がわかれば何ができるかと言ったら、そこからテストコードのテンプレートを生成することができると。
前提条件としてきちんとクラスの役割が明確であるだとか、テストができる状態になっているというのはここに関連することで、ユースケースとか、書き方が統一されていれば比較的メタプログラミングによってテストコードを作るみたいなことはやりやすいんですけれども。これが人によってバラバラとか、そういった感じで作られていると、なかなかこういう生成は難しくなってきます。
続きまして、ダミーデータを簡単に作る方法ですね。テストを書いていて1番しんどいことは何かと言うと、たぶんダミーデータを作るのがとてもしんどいことだと思います。
巨大なクラスですと1つのユースケースにいくつものモデルが関連していたりして、何種類ものオブジェクトのダミーデータを作らなければならない。テスト用のダミーのデータを作らなければならないということで、これを手でやろうとするととてもしんどいと。
これまで話していたように、ユースケースのパースをしたりとか、メタプログラミングを使ってクラスごとにダミーデータのファクトリを作るっていう解決方法もあります。僕たちももともとそういうクラスごとのダミーデータを生成するという方法でこれを解決していたんですけれども。
クラスごとにファクトリを作らないといけないということで、手でやるとしんどい。生成するにしても、生成したファイルはけっこう膨大なのでメンテナンスのコストが大きくなってしまう。加えて、モデルの書き方がちょっと変わったりすると全体的に影響が出たりすることもあります。
では、これを楽に解決する方法はないのかということで、辛くない解決方法。どんな型のインスタンスだろうが作れる汎用的なファクトリというものを定義できればこれを解決できると考えました。
具体的にどうやってそれを実現するかと言うと、あらゆる型ということなので、あらゆる型が実際どんなかたちをしているのかを一般化することができれば、どんな型のインスタンスでも作れるファクトリというものが作れます。そこで登場するのが直和型と直積型の考え方です。
直和型というのはA+Bで、AかBのどちらかを取るような型というふうに定義します。直積型というのはA×Bということで、AとBの2つの要素を持つような型。
直和型というのはEitherとか聞いたことあると思いますが、そういったものです。直積型というのはTupleとかですね。そういったデータ構造だと思っていただければと思います。
こういったかたちにいろんな型は書き換えることができます。
例えばAnimalという抽象クラスがあって、それを継承するDog、Catっていうクラスがあったとします。AnimalはDogかCatのどちらかなので、DogとCatの直和であると。
Catというのは、nameというStringの要素とageというIntの要素を持っている直積であると定義して、直和と直積だけで記述することができるます。
これを使って、構造に関しては全部直和と直積のかたちで言葉は定義できるので汎用的なファクトリを作ることができる。実際にどのように実装するかと言うと、ジェネリックプログラミングライブラリを使うという方法がたぶん1番一般的だと思っています。
Scalaだったらshapelessっていうライブラリなんですけど、そのあたりを使って作るのが一般的です。もう1つはメタプログラミングを使った方法ですね。自分で自力で実装するという方法があります。
我々のプロダクトではScalaを使っていて、実際にこのようなどんな型のダミーデータでも作れるファクトリというものを実装したんですけれども、それがこの例ですね。
1番上の行で、Dogというクラスを定義しました。その真下でTestObject [Dog] というふうに書いて、型引数を渡しています。これによってDogのダミーデータが生み出されました。
ここで注目してほしいのは、TestObjectというものを書いている段階ではDog型のダミーデータをどのように作るかを、実はTestObjectに与えていません。
これが実際に中では直積と直和のかたちに置き換えて、そこからまた戻してというようなことをやって作っているんですけれども。このようにしてイントロの作り方、Stringの作り方を個別に与えるだけでどんなインスタンスでも作れるようなダミーデータのファクトリを作ることができました。
今回はお話ししませんが、Stateモナドを使うことによって、これは固定のダミーデータなんですけど、ものよって違うダミーデータを作ることも可能になってきます。
ということで、まとめです。コード生成を使って怠惰にプログラミングをしましょう。メタプログラミングとかジェネリックプログラミングみたいなものを使っていくといいんですけれども。
こうしたことは言語に依存するところがあると思うので、メタプログラミングやあまり強くない言語を使っている場合にはパーサを使ってコード生成をすることでなんとかすることができます。
以上になります。ご静聴ありがとうございました。
(会場拍手)
司会者:高橋さん、ありがとうございました。ご質問がある方は挙手お願いいたします。ないですか? じゃあ僕から。僕、実はAndroidエンジニアなんですが、テストとかも書かなきゃいけなくてすごくしんどい気持ちにはなっています。そこで、実際にこれを導入してどれくらい楽になったのかなというのは気になります。
高橋:とくに効果が大きかったのは、汎用ファクトリです。本当に最初の状態ってファクトリすら定義されていなくて、テストを1個書くごとにダミーデータを上からガーっと書いて。1つのテスト書くのに1,000行書く、みたいなことがあったりして大変でした。
ダミーデータを作って、さらにテンプレートの生成みたいなものを組み合わせることによって正常系のテストを1個書くくらいだったら、自分で手で書かなきゃいけないのは数十行とかそのくらいで済むようになりました。生産性の点に関してはだいぶよくなったのかなと思います。
司会者:ありがとうございます。それでは、これで終了とさせていただきます。高橋さん、改めてありがとうございました。
(会場拍手)
2025.02.06
すかいらーく創業者が、社長を辞めて75歳で再起業したわけ “あえて長居させるコーヒー店”の経営に込めるこだわり
PR | 2025.02.07
プロジェクトマネージャーは「無理ゲーを攻略するプレイヤー」 仕事を任せられない管理職のためのマネジメントの秘訣
2025.02.04
日本企業にありがちな「生産性の低さ」の原因 メーカーの「ちょっとした改善」で勝負が決まる仕組みの落とし穴
2025.02.05
「納得しないと動けない部下」を変える3つのステップとは マネージャーの悩みを解消する会話のテクニック
2025.02.06
落合陽一氏や松尾豊氏の研究は社会に届いているか? ひろゆき氏が語るアカデミアの課題と展望
2025.01.07
1月から始めたい「日記」を書く習慣 ビジネスパーソンにおすすめな3つの理由
2025.02.05
エンジニアとして成功するための秘訣とは? ひろゆき氏が語る、自由な働き方を叶えるアプリ開発とキャリア戦略
2025.02.03
手帳に書くだけで心が整うメンタルケアのコツ イライラ、モヤモヤ、落ち込んだ時の手帳の使い方
2025.02.03
「昔は富豪的プログラミングなんてできなかった」 21歳で「2ちゃんねる」を生んだひろゆき氏が語る開発の裏側
2025.02.10
A4用紙を持ち歩いて殴り書きでアウトプット コクヨのワークスタイルコンサルタントが語る、2種類のメモ術
【手放すTALK LIVE#45】人と組織のポテンシャルが継承されるソース原理 ~人と組織のポテンシャルが花開く「ソース原理」とは~
2024.12.09 - 2024.12.09
【著者来館】『成果を上げるプレイングマネジャーは「これ」をやらない』出版記念イベント!
2025.01.10 - 2025.01.10
片付けパパ対談【特別編】 整理術×行動術×メモ術で、仕事も人生も自在にデザイン!
2024.12.16 - 2024.12.16
日本を変える 中小企業リーダーズサミット2025
2025.01.30 - 2025.02.12
【必見】納得しない部下を動かす!マネジメントの裏技とは?
2024.12.16 - 2024.12.16