←記事一覧

ライブラリーとフレームワークの違い — 制御の反転を理解する

ライブラリーとフレームワークの違いを、制御の反転(IoC)という観点からコード例を使って説明します。

Software EngineeringArchitectureDesign Patterns

「ライブラリー」と「フレームワーク」はどちらもソフトウェア開発でよく使う言葉ですが、違いを聞かれるとはっきり答えにくい言葉でもあります。両者を分けるのは、どちらがどちらを呼ぶかです。開発者のコードがライブラリーを呼ぶのに対し、フレームワークは開発者のコードを呼びます。この記事では、この違いを制御の反転(Inversion of Control, IoC)という考え方からコード例で説明します。

ライブラリーとは

ライブラリーは、特定の機能を提供するコードの集合体です。開発者が自分のコードからライブラリーの関数やクラスを呼び出して使います。

制御の主導権は開発者のコードにあります。ライブラリーの機能をいつ、どのように、どの順番で使うかは、すべて開発者が決めます。

# ライブラリの例: requests
import requests
 
# 開発者が制御の主導権を握っている
response = requests.get("https://api.example.com/users")
data = response.json()
 
for user in data:
    print(user["name"])

この例では、requests ライブラリーをいつ呼び出すか、結果をどう処理するかを開発者のコードが決めています。

代表的なライブラリー:

言語ライブラリー用途
PythonRequestsHTTP クライアント
JavaScriptLodashユーティリティー関数
JavaGuavaコレクション・キャッシュ
Gozap構造化ロギング
ClibcurlHTTP/ネットワーク通信

フレームワークとは

フレームワークは、アプリケーション全体の骨格を提供するソフトウェア基盤です。アプリケーションの構造と実行フローはフレームワークが決め、開発者はフレームワークが用意した拡張ポイントに自分のコードを差し込みます。

制御の主導権はフレームワーク側にあります。

# フレームワークの例: Flask
from flask import Flask
 
app = Flask(__name__)
 
# フレームワークが「いつ」この関数を呼ぶかを決める
@app.route("/users")
def get_users():
    return [{"name": "Alice"}, {"name": "Bob"}]
 
# フレームワークにアプリケーションの実行を委ねる
if __name__ == "__main__":
    app.run()

この例では、get_users 関数をいつ呼び出すかはフレームワーク(Flask)が決めています。HTTP リクエストが /users に届くと、Flask が開発者のコードを呼び出します。

代表的なフレームワーク:

言語フレームワーク用途
PythonDjango, FlaskWeb アプリケーション
JavaScriptNext.jsフルスタック Web
JavaSpringエンタープライズアプリケーション
RubyRuby on RailsWeb アプリケーション
GoGinWeb API

制御の反転(Inversion of Control)

ライブラリーとフレームワークの違いは、制御の反転(Inversion of Control, IoC)と呼ばれるソフトウェア設計の原則で説明できます。

  • ライブラリー: 開発者のコード → ライブラリーを呼ぶ(開発者がコールする)
  • フレームワーク: フレームワーク → 開発者のコードを呼ぶ(フレームワークがコールバックする)

この呼び出し関係の逆転が「制御の反転」です。"Hollywood Principle: Don't call us, we'll call you"(ハリウッドの原則: こちらから電話するので、電話してこないでください)とも呼ばれます。Martin Fowler は IoC に関する記事 で、この原則をフレームワークとライブラリーを分ける重要な要素として挙げています。

コードで比較する

同じ HTTP サーバーでも、ライブラリー的に書くかフレームワーク的に書くかでコードの構造は大きく変わります。

ライブラリー的なアプローチ(Go の net/http を直接使う場合。ハンドラーは net/http から呼ばれるが、アプリケーション全体の構造はほとんど強制しない):

package main
 
import (
    "encoding/json"
    "log"
    "net/http"
)
 
func main() {
    // 開発者がサーバーの構築、起動、アプリ構造の大部分を制御する
    mux := http.NewServeMux()
 
    mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
        users := []map[string]string{
            {"name": "Alice"},
            {"name": "Bob"},
        }
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(users)
    })
 
    log.Fatal(http.ListenAndServe(":8080", mux))
}

フレームワーク的なアプローチ(Next.js の App Router):

// app/users/page.tsx
// フレームワークがルーティング、レンダリング、配信を制御する
 
export default async function UsersPage() {
  const users = [
    { name: "Alice" },
    { name: "Bob" },
  ];
 
  return (
    <ul>
      {users.map((user) => (
        <li key={user.name}>{user.name}</li>
      ))}
    </ul>
  );
}

Next.js の例では、ファイルの置き場所がルートになり、コンポーネントをいつレンダリングするかはフレームワークが管理します。開発者が書くのは「何を表示するか」の部分です。

よくある誤解

「React はライブラリー?フレームワーク?」

React は公式サイトで自らを "The library for web and native user interfaces"(Web とネイティブのユーザーインターフェースのためのライブラリー)と説明しています。React 単体はコンポーネントのレンダリングを担い、ルーティングなどは別のライブラリーに任せます。

ただし、コンポーネントのライフサイクルや再レンダリングのタイミングは React が制御するので、フレームワーク的な面もあります。Next.js は React の上にルーティング、データフェッチ、ビルドシステムなどを加えたフレームワークです。

実際に使うときは、どちらに分類されるかより、どの処理を React が制御し、どこを開発者が決めるのかを見るほうが役に立ちます。

「サイズが大きいとフレームワーク?」

コードの規模では区別できません。小さなフレームワークも、大きなライブラリーもあります。

  • Express.js — 軽量ですがフレームワークです(リクエスト処理の制御フローを Express が管理する)
  • TensorFlow — 巨大ですが、多くの場合はライブラリーとして使われます(モデル構築やトレーニングループを開発者が制御できる。一方で Keras などの高水準 API はフレームワーク的な規約を加える)

ライブラリーとフレームワークの選び方

次の表は、制御がどちら側にあるかによって生じやすい違いを、一般的な傾向としてまとめたものです。

観点ライブラリーフレームワーク
制御開発者が制御フレームワークが制御
柔軟性高い(自由な組み合わせ)低い(規約に従う)
学習コスト低い(必要な API だけ学ぶ)高い(全体の規約を理解する必要がある)
一貫性チームに依存フレームワークが強制
開発速度初期は速い、規模拡大で低下しやすい初期は遅い、規模拡大で安定しやすい
適したケース特定機能の追加アプリケーション全体の構築

実際の開発では、フレームワークの中でライブラリーを使うことがよくあります。例えば、Next.js(フレームワーク)のアプリケーションで date-fns(ライブラリー)を使って日付をフォーマットする、といった組み合わせです。

まとめ

ライブラリーは開発者のコードが呼び出す道具で、制御の主導権は開発者にあります。フレームワークは開発者のコードを呼び出す基盤で、主導権はフレームワークにあります。両者の違いは制御の反転(IoC)、つまり「誰が誰を呼ぶか」です。

実際のツールはきれいに二分できるわけではなく、その間のどこかに位置します。ツールを選ぶときは、制御がどちら側にあるかを確かめておくと判断しやすくなります。