/note/tech

ソースコードを整理して開発を高速化する

要約:

■ 1. 基本方針

  • 極力単機能になるまで分解する: コードを小さな意味のある機能に分離することを重視
  • 単純な機能を組み合わせ複雑な機能を作成する: 分解した機能を組み合わせて全体を構築

■ 2. コード開発における時間配分の実態

  • 読む時間の方が長い: キーボードでコードを書く時間よりも読む時間の方が長くなりがち
  • 読むシーン:
    • 自分が書いたコードの確認
    • 他の人が書いたコードのレビュー
    • 不具合発生時の調査
    • 改修時のあたりをつける作業
  • AI使用による変化: AIを使うようになってこの傾向はさらに強くなっている

■ 3. テストと動作確認に要する時間

  • 動作保証までの時間: コードを書く時間よりも動作保証できるようになるまでの時間の方が長くなることがしばしばある
  • 動作保証の作業:
    • 自動テストの作成
    • 手動でのUI操作
    • curlを使ったAPI動作確認

■ 4. 開発効率向上のための重視点

  • 小さい意味のある機能に分離する: 理解しやすく管理しやすいコードにする
  • 動作保証されてるコードの塊を作る: 再利用可能で信頼性の高いコンポーネントを構築

■ 5. ワーキングメモリーの制約

  • 短期記憶の限界: 人のワーキングメモリーで記憶しておけるのは3〜5個程度
  • コンテキスト増加の問題:
    • 覚えておかないといけないコンテキストが増えるとワーキングメモリから溢れる
    • 読み直しが発生する
    • 間違った情報で補完してしまう
  • ソースコードへの影響: 複雑な処理がフラットに書かれていると、コンテキストとして読んだコードを覚えておく必要が出てくる

■ 6. API処理の例(改善前)

  • 処理内容:
    • 別サービスのAPIからデータを取得(キャッシュがあればキャッシュから取得、有効期限の管理を含む)
    • ユーザーのステータスが退会済みであればエラーにする
    • ユーザーの購入情報を取得(同様にキャッシュ処理を行う)
    • 上記データを加工してAPIのレスポンスとして返す
  • 問題点: 一つの処理として書くと処理が複雑になり、読み解くのに時間がかかる

■ 7. サブルーチンへの分解(改善後)

  • fetchUserIfNeeded関数: キャッシュ確認とユーザーデータ取得を担当
  • fetchPurchases関数: 購入データの取得を担当
  • validateUserStatus関数: ユーザーステータスの検証を担当
  • getUserHandler関数: 全体の流れを俯瞰できるメインルーチン
  • 効果:
    • 各サブルーチンは短い処理で機能を把握しやすい
    • メインルーチンは全体の流れを俯瞰できる
    • 関数名が処理内容を表すため、人が読んでも理解しやすくAIのコンテキストも減らせる

■ 8. 共通化の必要性

  • キャッシュ機構の共通化: キャッシュ処理は共通化できる
  • 呼び出し側の関心(期待):
    • キャッシュがあればキャッシュからデータを返却する
    • キャッシュがなければfetchしてDBにキャッシュする
    • 有効期限が切れればキャッシュを更新する
  • 再利用性: これらの関心は他のfetch処理でも同様に存在する

■ 9. withCache関数の実装

  • 汎用的なキャッシュ関数: ジェネリック型を使用した汎用的なキャッシュ機能の実装
  • パラメータ:
    • db: データベース接続
    • key: キャッシュキー
    • fetcher: データ取得関数
    • ttl: キャッシュ有効期間(デフォルト1時間)
  • 処理フロー:
    • キャッシュチェック
    • 有効期限内ならキャッシュを返却
    • 期限切れなら削除
    • 新規取得してキャッシュに保存

■ 10. 共通化後のコード

  • fetchUserIfNeeded関数の簡略化: withCache関数を使用してキャッシュ処理を委譲
  • 可読性の向上: 元々のソースから必要な情報を読み取りやすくなった
  • コードの整理: 各関数の役割が明確になり、全体の構造が把握しやすい

■ 11. テストの効率化

  • 単体テストの作成: キャッシュ処理単体で自動テストを作成できる
  • テストケースの明確化: 呼び出し側の関心をそのままテストケースにできる
  • テストの再利用性: 新しいケースで関数を再利用する際、キャッシュの有効期限処理等はこの関数の単体テストで保証され、新しくテストを追加する必要がない

■ 12. 開発高速化の効果

  • 動作保証されたコードの塊: いくつも作ることでテストに使う時間を減らせる
  • 開発時間の削減: 結果として開発の高速化につながる
  • 積み重ねの重要性: 派手な効果(N倍の効率化)ではないが、こういった積み重ねで開発を高速化する

■ 13. まとめ

  • テーマ: 開発の高速化を実現するために日頃心掛けていること
  • アプローチ: 小さな改善の積み重ねによる持続的な開発効率向上
  • 目的: この記事が誰かの役に立つことを期待