AI時代に求められるのは、コードの速さか、可読性か
AI時代に求められるのは、コードの速さか、可読性か

AI時代に求められるのは、コードの速さか、可読性か

はい、どうもこんにちは佐藤です!

コードを書いてきて 20 年ほど。IT を仕事にしてからは 10 年ほどになります。その間にいくつも波を見てきましたが、ここに来て、また大きな波が来ましたね。

そう、AI です。

AI がコードを書く時代になって、ふと考えたことがあります。コードに求められるのは、速さなのか、可読性なのか。

私がこの業界に来た 10 年前、ソースコードには速さが求められていました。それが今では、すっかり可読性の時代です。では、AI 時代はどちらを取るべきでしょうか?

私の答えは……。

やはり可読性です!

しかも、人間のためだけではありません。AI のための可読性です。

その理由を書いていきますね!


10 年で、評価の軸はひっくり返った

まずは昔話から。

10 年前の評価基準では、速いコードが書けることが重視されていました。

  • for ループ 1 回の中に、処理を詰め込む
  • ストアドプロシージャの力を利用して、なるべく速く処理する

ループを 2 回回すなんて、もったいない。1 回で済むなら、そこに全部入れる。そういうコードが「できる人のコード」だったのです。

でも今では、マシンスペックが上がりました。コードの構文も、stream のような書き方が当たり前になっています。

  • 1 回の for ループの中には、原則 1 処理
  • アグリゲートの考え方でまとまりを作る
  • 極力、ストアドやクエリの力を使わない

こういう作りが主流になりました。少しくらい遅くても、読めることのほうが大事。評価の軸が、10 年でひっくり返ったわけです。

この流れは、以前 SQL の結合禁止は良いルールなのか や 4層かクリーンアーキテクチャかは、使うDBが決める でも書きました。

では、AI がコードを書く時代に、この振り子はまた「速さ」へ戻るのでしょうか? 私は戻らないと考えています。理由は 3 つ。


いざという時、読むのは人間

1 つ目は、いざという時は、人間が読む必要が出るからです。

不具合の対応も、AI に任せる時代になってきました。ログを渡せば原因を探してくれますし、修正案も出してくれます。

でも、その修正が正しいかどうかを最後に判断するのは人間です。

特に次のようなドメインでは、どうしても人間が読むことになります。

  • セキュリティに関わる処理
  • 金融の計算や取引
  • 個人情報を扱う処理

以前 AIがコードを書く時代にコードレビューは不要 と書いた私が言うのも何ですが、あれは「普段から読まなくて済む仕組みを作ろう」という話でした。読まなくて済む仕組みがあっても、いざという時に読めないコードでは困りますよね。

障害対応の夜に、ループ 1 回へ詰め込まれた 300 行と向き合う。想像するだけで胃が痛くなりませんか?


AI も、読みにくいコードでは間違える

2 つ目が、今回いちばん言いたいことです。

AI も、読みやすいコードであればハルシネーションが少なくなります。

これは実際に痛い目を見た話です。

私は以前、論理結合の激しい処理を書いてしまったことがありました。

  • A の処理をして、DB にあるデータが入る
  • そのデータが入っている前提で、B の処理をする

A と B は、コードの上では離れたところにあります。でも、DB を挟んでがっちり結びついていたのです。

ある日、AI に A の修正を頼みました。AI は A を正しく直してくれます。ところが、B は直されていませんでした。 A が DB に入れるものが変わったのに、それを前提にしている B はそのまま。結果、不具合が発生しました。

AI が悪かったのでしょうか?

私はそうは思いません。影響範囲が読めない書き方をしていたのは、私のほうです。A のコードだけを読んでも、B がそれに依存していることはどこにも書いていませんでした。人間が読んでも見落とすコードを、AI が見落とさない理由はありませんよね。

目次のように書くと、AI にも影響範囲が見える

では、どう書けばよかったのか。

私が意識しているのは、パラグラフライティングのような書き方です。メインの関数が「目次」になっていて、中身はプライベートメソッドに分かれている形ですね。

イメージを書いてみます。まずは、ループ 1 回に詰め込んだ書き方から。

def close_month(self, orders):
    for order in orders:
        if order.status == "shipped":
            order.status = "billed"
            self.repo.save(order)
            invoice = Invoice(order.customer_id, order.amount)
            self.invoice_repo.save(invoice)
            # ……ここに割引、税、通知が続いていく

次に、目次のように書いた形です。

def close_month(self, orders):
    shipped = self._pick_shipped(orders)
    self._mark_as_billed(shipped)       # A: 請求済みにして保存する
    self._issue_invoices(shipped)       # B: 請求済みを前提に請求書を作る

下の形なら、メインの関数を読むだけで「A のあとに B があって、B は A の結果を前提にしている」ことが分かります。影響範囲が、目次にそのまま出てくるわけです。

AI に A の修正を頼んだときも、目次を読めば B が隣にいることに気づけます。気づける材料がコードの上にあるかどうか。ハルシネーションが減るかどうかは、そこで決まるのだと思っています。

さらにドメイン駆動設計で作っていれば、ドメイン同士が分離していることも、AI に知らせられます。


AI は、読みやすいコードを手本に書く

3 つ目は、最近のコードは読みやすさ重視で書かれているからです。

AI がコードを書くとき、手本にするのはプロジェクトの中にある既存のコードですよね。そこが読みやすさ重視で書かれていれば、AI が参考にするときの負担になりにくい。新しく書くコードも、同じ形にそろっていきます。

逆に、ストアドに処理が寄っていると、AI にとってはつらい構成です。

  • ロジックが DB の中にあって、アプリのコードを読んでも全体が見えない
  • 実データがないと、テストが難しい

AI に実装させて、テストで動くことを確かめてから人間がレビューする。そういう回し方をしたいなら、テストしやすい形であることは欠かせません。実データを用意しないと確かめられない処理は、AI が自分で動作を確認できないのです。

速さのためにストアドへ寄せるほど、AI に任せられる範囲は狭くなっていきます。


まとめ

というわけで、AI 時代も今の路線で進むのが良いよね!って話でした!

あ。正確には、人間のためだけじゃなく、AI のために可読性を取ろう って感じですねっ。

速さはマシンが補ってくれます。でも、影響範囲が読めないコードの間違いは、人間も AI も同じように踏んでしまう。メインの関数を目次にして、何がどこに依存しているかをコードの上に書いておくこと。それが、AI に安心して任せるためのいちばんの近道です。

ぜひみなさんも、自分のコードを「AI が読んでも影響範囲が分かるか」という目で見直してみてください!

この記事をシェアする