現在、ある仕事でSequelizeというNode.js用のORM(Object-relational mapping)を使っています。現在Node.jsまわりではPrismaというORMが人気なようですが、npm trendsを見ると現時点でもSequelizeの方がダウンロード数が多いようです。
今回はじめてSequelizeを使うので仕様の詳細がわからず戸惑っています。ORMを使うとRDBが簡単に使えるライブラリーだったはずですが・・・・、私は長年Ruby on Railsを使っているのでORM初心者ではないはずですが・・・・。😅
DeepAIが生成した画像です
RDBは難しい?
RDBは、現在でも色々なシステム(サービス)の核として使われていますが、純粋なプログラマー(?)からみると少し違う世界のように思えます。
1. RDBは関係モデルをベースにしている
RDBでは、データは表のような2次元の入れ物に格納されます。表は多数持て複雑なデータ構造は表と表に関連(リレーション)を持たせる事で実現します。
また、データは行(レコード)の集合として扱われます。
2. RDBを操作するにはSQLという宣言型言語を使っている
一般的なプログラミング言語は手続きを記述する手続き型言語ですが、宣言型言語では「このようなデータが欲しい」などの宣言を定義・記述します。
したがってRDB/SQLを習得するには時間もかかります。
初期のRDBプログラミング
ORMが現れる前は、RDBへの接続ライブラリーを使い、RDBからデータを取得したり、更新したりしていました。
以下のサンプルコードではpgという低レベルのNode.js用PostgreSQL接続ライブラリーを使い、データベース内のusersテーブルから取得した値をコンソールに表示します。
import pg from "pg";
const dbConfig = { .... }; // ← ①
const client = new pg.Client(dbConfig); // ← ②
client.connect(); // ← ③
const res = await client.query("SELECT * FROM users"); // ← ④
res.rows.forEach((row) => { // ← ⑤
console.log(`email: ${row.email}, name: ${row.name}`); // ← ⑥
});
await client.end(); // ← ⑦
- ① 接続するデータベースサーバーの情報、ここでは詳細は省略しました
- ② データベース接続インスタンスの生成
- ③ データベース・サーバーへの接続
- ④ SQL文の実行、結果がres変数に代入される
- ⑤ res.rowsは取得されたデータ(レコード)のオブジェクトの配列です
- ⑥ 配列内の1要素はレコードに対応するJavaScriptのオブジェクトで、
row.email
のように値が取得できます - ⑦ データベース・サーバーの接続解除
初期のRDBプログラミングの問題点
上のような初期のRDBプログラミングには、以下のような欠点がありました。
1. SQLやRDBの原理を知らないとコードが書けない
RDBの原理やSQLを知らないでプログラムが書ける事の方が異常なのかもしれませんが。
プログラム言語をやっと覚え何とかプログラムが書けるようになったばかりの新人に、SQL言語を教えると頭が混乱してしまうのを何度も見ました。
2. テーブルから取得したデータを、コード内のデータ構造に変換するのが面倒
上の例ではデータベースからの取得結果はJavaScriptのオブジェクトになっているのでシンプルですが、プログラミング言語が扱いやすいHash等をサポートしてない場合は煩雑になります。
とくに、Javaの標準であるJDBCやWindows環境の標準であるODBCなどではSQLから取得したデータをプログラム内のデータ構造に変換するコードが煩雑にがちでした。
当時の雰囲気を知りたい方は@IT - JDBCによるDBへの接続と検索の実行等をごらんください。
ORM登場
私がはじめて使ったORMはHibernateで、テーブルをJavaのオブジェクトにマップできましたが、当時はXMLで複雑な設定ファイル書く必要があり、設定ファイルのちょっとしたミスで動かず半日悩みました。😅
当時の雰囲気を知りたい方は@IT - Hibernateで覚えるO/RマッピングとBeanの常識等をごらんください。
当時のORMライブラリーやフレームワークは汎用性を考え、大げさな作りになっていた。しかも設定ファイルが必要で、それがXMLという複雑な言語でした。その後HibernateはJava言語のアノテーション(Annotation)を使うように進歩していきましたが、私がORMを使う事はなくなりました。
また、名著「エンタープライズ アプリケーションアーキテクチャパターン」— Patterns of Enterprise Application Architectureでも第3章、第10〜13章でORMに付いて深く考察されています、パターンとして以下に分類されています。
Ruby on Railsの衝撃
2005(2004)年に登場した Ruby on Railsは、現在の色々なフレームワークやORMライブラリーに大きな影響を与えました。
特にORMのActive Recordは、
- CoC (Convention over Configuration)思想により、設定ファイルやアノテーション等を書かずに、テーブルとオブジェクトをマッピング出来る
- RDB/SQLの知識がそれほどなくてもプログラミングできる
- 高機能で、関連情報も簡単に取得できる
- テーブルの作成・変更履歴を管理できるマイグレーション(migration)が便利
Ruby on Rails以後に生まれたフレームワークやORMライブラリーは実装言語によらず何らかの形でRuby on Railsに影響を受けています。
ORMの欠点?
その後、システム開発にはORMを使う事が普通になりました。
今回SequelizeというORMに触れてみると、Active Recordに似てるので大枠での使い方はわります、しかし Active Recordではない! という事にぶち当たります。
Active Record(Ruby on Rails)の行き過ぎたCoCに対する反省からか、Sequelizeはモデルに書かなければならない設定項目が多数あります。当然ですが、その記述方法はActive Recordとは違います。
また、ORMのサポートするAPI(関数、メソッド)もORM毎に違います。似ているAPIが多いですが、Active Recordと同じではありません。
対してSQLは標準化されています。複雑なSQL文でも、ほぼ全てのデータベース実装で動きます。
何だか、不思議な感じですね。