【ITニュース解説】Domain specific language versus design patterns
2025年09月13日に「Dev.to」が公開したITニュース「Domain specific language versus design patterns」について初心者にもわかりやすく解説しています。
ITニュース概要
ソフトウェア開発手法のDSL(ドメイン固有言語)とデザインパターンを比較する。DSLは、SQLのように特定の処理に特化し、データ処理効率化や不要なクエリ防止に役立つ。コード意図は明確になるが、初期設計が重要だ。デザインパターンは柔軟だが、複雑な処理では理解が難しくなる。ドメインの行動が明確ならDSL、それ以外はデザインパターンが有効だ。
ITニュース解説
システムエンジニアを目指す初心者の皆さんは、日々の開発において、いかに効率的で分かりやすいコードを書くかという課題に直面する。この課題に取り組む上で、「抽象化」という考え方と、「ドメイン固有言語(DSL)」、そして「デザインパターン」という二つの強力なツールがよく議論される。今回のニュース記事は、これら三つの概念、特にデータアクセスにおけるDSLとデザインパターンのメリット・デメリットを深く掘り下げている。
まず、「抽象化」とは、複雑なものの詳細を隠し、もっと単純な形で扱えるようにする考え方のことだ。例えば、自動車を運転するとき、エンジンの複雑な仕組みを知らなくても、ハンドルやアクセルという抽象化されたインターフェースを通して操作できるのと同じである。ソフトウェア開発では、この抽象化がコードの読みやすさや保守のしやすさに直結する。
記事の筆者は、特にデータストレージ、つまりデータベースとのデータのやり取りにおける抽象化に注目している。具体的な例として、PHPでよく使われるORM(Object-Relational Mapping)と呼ばれる技術が登場する。ORMは、データベースのテーブルをプログラムのオブジェクト(部品)として扱えるようにするもので、SQL(データベースを操作するための言語)を直接書かなくても、オブジェクトを操作する感覚でデータベースのデータを扱える便利なツールだ。
記事では、Laravelの「Eloquent」とDoctrineの「ORM」という二つの異なるORMが比較されている。筆者は、これら二つのORMで、データベースのフィールド名(カラム名)を扱う際の抽象化レベルに違いがあることを指摘している。Eloquentの場合、プログラムのコードで直接データベースのカラム名を指定するため、もし指定したカラム名がデータベースに存在しないと、データベース自体がエラーを返す。これはデータベースの実装に依存する、比較的低いレベルのエラーと言える。一方、DoctrineのORMでは、プログラムのモデル(オブジェクト)の中でカラム名を定義し、そのモデルを通して操作する。そのため、もしプログラム内で誤ったカラム名を指定しても、データベースに問い合わせる前にORMの層でエラーを検出できる。これは、より高いレベルでの抽象化が実現されており、開発者にとっては早い段階で間違いに気づきやすいというメリットがある。
この違いが、筆者を「Doctrine Query Language(DQL)」というものに導くきっかけとなる。DQLは、Doctrine ORMが提供する、特定の「ドメイン」(ここではデータ操作の領域)に特化した言語、つまりDSLの一種だ。DQLは、データベースを操作する標準的な言語であるSQLの構文に非常に近い形をしている。SQL自体も、データベースという特定のドメインに特化したDSLの代表例だ。筆者は、プログラムコード中に直接書き込まれる短い文字列(マジックナンバーのように、何を表すのか分かりにくい値)を避けるべきだと考えており、DQLのように、データ操作の内容を長く明確な文字列で表現する方が、デザインパターンを使った解決策よりも、提供される抽象化がより分かりやすいと感じたようだ。
ここで、「デザインパターン」とは何かについても触れておこう。デザインパターンとは、ソフトウェア開発でよく遭遇する問題に対して、過去の経験から導き出された「効果的な解決策のひな形」のようなものだ。特定のプログラミング言語や技術に限定されず、さまざまな状況に応用できる汎用的な知恵と言える。記事でクエリビルダーという言葉が出てくるが、これはSQL文を組み立てるためのオブジェクト指向的なインターフェースを提供することが多く、特定のデザインパターン(例えばビルダーパターン)が適用されているケースが多い。
筆者は、デザインパターンが抱える可能性のある問題点として、クエリビルダーとDQLの比較を通して説明している。具体的には、データ取得後の処理方法と、意図しないデータベースアクセスの発生についてだ。
最初の大きな違いは、データがどのように処理されるかという点にある。クエリビルダーを使った場合、まずデータベースから必要なデータを取得し、その後、プログラムのコード(例えばPHPのmap関数など)を使って、取得したデータを加工したり、必要な情報を抽出したりする。これに対し、DQLを使った場合は、SQLに近い形でデータベースに直接、データの抽出や加工方法を指示できる。これにより、データがプログラムに渡される時点で、すでに必要な形に整形されていることが多い。これは、データ処理の負荷をデータベース側で行うため、特に大量のデータを扱う際に、プログラム側の処理を簡素化し、パフォーマンスを向上させる可能性がある。
次に、あまり気づかれにくいが重要な違いとして、「意図しない追加のSQLクエリ」の発生が挙げられる。クエリビルダーやORMの自動的な機能を使うと、プログラムのコード中でオブジェクトのプロパティにアクセスした際に、裏側で追加のデータベース問い合わせが走ってしまうことがある。これは「N+1問題」とも呼ばれ、例えば1つのレコードを取得した後、そのレコードに関連するN個の情報を取得するためにN回追加でデータベースに問い合わせてしまうような状況を指す。これはパフォーマンスの低下に直結する。DQLはSQLの構文に非常に近いため、開発者はどのようなSQLクエリが実行されるかを明確に意識しやすく、このような意図しない追加クエリの発生を防ぎやすいというメリットがある。
筆者は、デザインパターンが「コードの推論を容易にする」ことを目的とする一方で、DSLは「実行すべきアクションの推論を容易にする」ことを目的としていると考えている。つまり、デザインパターンはプログラムの構造や部品間の関係性を理解しやすくするのに対し、DSLは「何をしたいのか」という業務上のアクションを直接的に表現しやすくする、という違いがある。アクションが複雑になるほど、デザインパターンはシステム全体の結合度を緩やかに保とうとするため、その構造を理解するためのメンタルモデル(頭の中で描くシステムのイメージ)が大きくなりがちだ。しかし、DSLは特定のドメインに特化しているため、そのドメイン内のアクションに関しては、よりシンプルで直感的なメンタルモデルで理解できることが多い。
もちろん、DSLにも課題がある。主な問題点として、文字列として表現されるDSLを設計する際には、現在の要件だけでなく、将来発生するであろう要件にも対応できるように、最初から綿密な計画と設計が必要になる点が挙げられる。一般的なプログラムコードのように、状況に応じて柔軟に修正を加えていくというイテレーション(反復開発)が難しい場合がある。また、DSLが文字列として定義される場合、その文字列を解釈して実際のコードに変換する「裏側の仕組み」が必要になる。これは、デザインパターンを使った一般的なプログラミングよりも、内部的な処理の「歯車」が多くなる、つまり実装が複雑になる可能性があることを意味する。DSL自体が「コードのフロントエンド」のような役割を果たし、その背後でより複雑な変換処理が動いていると考えると分かりやすいだろう。
最終的に、筆者はDSLを採用するべきタイミングとして二つのパスを示している。一つは、解決したい問題領域(ドメイン)におけるアクションが、プロジェクトの初期段階から明確に理解されている場合だ。このような状況では、最初からDSLを導入することで、そのドメインに特化した分かりやすく効率的なコードを書ける。もう一つは、プロジェクトがしばらく進行し、ドメイン内のアクションがある程度固まってきた段階で、DSLの導入がコードの理解しやすさやエラーの少なさにつながるかどうかを評価する場合だ。これら二つのケース以外では、より汎用的な解決策であるデザインパターンを用いるのが適切であると結論付けている。
システム開発において、DSLもデザインパターンも、それぞれ異なる目的と強みを持つ重要なツールだ。どちらか一方が常に優れているということはなく、プロジェクトの性質やドメインの複雑さ、開発チームの習熟度など、さまざまな要素を考慮して適切に使い分ける知恵が求められる。今回の記事は、その使い分けを考える上での貴重な示唆を与えてくれるだろう。