サイトアイコン IT & ライフハックブログ|学びと実践のためのアイデア集

【授業レポート】システム開発(2年)第36週:DBマイグレーションとDAO設計を実装する

boy in green shirt

Photo by CDC on Pexels.com

システム開発(2年)の第36週は、設計したデータベースを実際に作り、アプリケーションから操作できる形へ進める実習でした。

前週に作成したER図とSQLを出発点に、DDLの実行、DAOの設計と実装、Service層との連携、ミニ動作テストまでを一つの流れとして確認しました。

第36週の到達点

今回の実習では、データベースとアプリケーションの間にある処理を、役割ごとに分けて実装しました。

実習前に押さえた用語

用語の関係を先に整理すると、実装のどの部分を確認しているのか判断しやすくなります。

今回の実習で扱った主な用語
用語 この授業での意味
DDL テーブルや制約など、データベースの構造を定義するSQLです。
マイグレーション DDLを実行して、データベースの構造を必要な状態へ作成または変更する作業です。今回はテーブル作成が中心でした。
DAO Data Access Objectの略で、SQLの実行や検索結果の取得など、データベースへのアクセスを担当する層です。
CRUD Create、Read、Update、Deleteの頭文字で、データの作成、読み取り、更新、削除を表します。
トランザクション 関連するデータベース操作を一つのまとまりとして扱い、成功時はコミットし、失敗時はロールバックする考え方です。

DDLを実行してテーブルと制約を確かめる

各班は、前週に作成したDDLを学習環境で実行し、テーブルが期待した構造になっているかを確認しました。

作成できたかどうかだけで終わらせず、制約とデータの関係まで試すことが今回の確認点です。

確認した五つの項目

実行結果を確認する中で、外部キーの設定漏れや制約の不足が見つかりました。

設計図を眺めるだけでは気づきにくい点も、実際にデータを登録し、検索すると確認できます。

マイグレーションを発展的に学ぶ場合は、DBマイグレーションの作成、適用、ロールバックの手順も参考になります。

DAOにデータベース操作を集める

続いて、図書館システムの書籍データを扱うBooksDaoを例に、DAOのインターフェースを検討しました。

画面や業務ルールの中へSQLを散在させず、データベース操作の窓口をDAOに集めることが狙いです。

設計した基本メソッド

メソッド名だけでなく、引数、返り値、データが見つからない場合の扱いまで決めると、DAOを呼び出す側の実装が曖昧になりません。

学習用の実装例

class BooksDao:
    def __init__(self, conn):
        self.conn = conn

    def get(self, book_id):
        cur = self.conn.cursor()
        cur.execute(
            "SELECT id, title, author, is_available FROM books WHERE id = %s",
            (book_id,),
        )
        return cur.fetchone()

    def create(self, title, author):
        cur = self.conn.cursor()
        try:
            cur.execute(
                "INSERT INTO books (title, author) VALUES (%s, %s) RETURNING id",
                (title, author),
            )
            new_id = cur.fetchone()[0]
            self.conn.commit()
            return new_id
        except Exception:
            self.conn.rollback()
            raise

このコードは、授業で扱った内容を示すための簡略例です。

掲載例は%s形式のプレースホルダを使っているため、SQLiteを含む別の接続ライブラリで試す場合は、そのライブラリに合う記法へ読み替えます。

プレースホルダとトランザクションの役割

プレースホルダは、SQLの命令部分と値を分けて渡す仕組みです。

検索IDや書籍名を文字列の連結でSQLへ埋め込まず、実行メソッドの引数として渡すことが、SQLインジェクション対策の基本になります。

トランザクションでは、処理が完了したときにコミットし、途中で例外が発生したときにロールバックします。

DAOの各メソッドで完結させるのか、複数のDAO操作をまとめるService側で管理するのかを決め、境界を統一することが設計上の確認点です。

ログについては、SQLや入力値を無制限に記録するのではなく、原因調査に必要な情報をそろえながら、取り扱いに注意すべき値を残さない方針を確認しました。

DAO、Service、UIの責務を分ける

Service層は、貸出可能かの判定や延滞時の処理など、アプリケーションの業務ルールを担当します。

UIからDAOを直接呼ぶのではなく、Serviceを間に置き、各層が担当する判断を分けました。

図書館システムでの責務の分け方
層 主な役割 今回の例
DAO データベースの読み書き 書籍の取得、登録、更新、削除
Service 業務ルールと処理の順序 貸出可否の確認、延滞時の処理、検索条件の検証
ControllerまたはUI 入力の受け取りと結果の表示 検索語の受け取り、一覧やエラーの表示

この分け方により、SQLを変更する場面と業務ルールを変更する場面を区別して考えられます。

テーブルからServiceまでを通して動かす

最後に、個別に作った部品を次の順序でつなぎ、ミニ動作テストを行いました。

  1. サンプルデータをテーブルへ登録する
  2. DAOでデータを読み取る
  3. Serviceで業務ルールを適用する
  4. 返された結果を確認する

例外が発生した班は、ログを手がかりに原因を探し、その場で修正しました。

特に確認が必要だったのは、外部キーによる参照関係と、NULLを許可しない列へ渡す値です。

レビューで見えた次の改善点

宿題と次週の実装

今回の宿題は、実装したクラスとユースケースの対応を図にして、次週の結合へ備える内容です。

  1. 各班のDAOクラス一覧とメソッド表を作成する
  2. DAOとServiceの簡易クラス図を一枚にまとめる
  3. 主要なユースケースを一つ選び、処理フロー図を作成する

次週はDAOとServiceをWebまたはCLIのUIへ接続し、ユースケース単位で動かします。

続きは、第37週のDAO、Service、UIをつなぐ実習で紹介しています。

第36週の振り返り

第36週では、ER図とDDLで表した設計を、DAOとServiceを通じて動く処理へ変えました。

データベース操作と業務ルールを分け、例外が起きた場合の戻し方まで決めることで、各コードが何を担当するのかを説明できる状態に近づきました。

この記事に関連する株式会社greedenの取り組み

DAOとServiceの責務を分ける学びは、保守しやすいWebシステム開発の土台になります。株式会社greedenは、要件定義からDBやAPIの設計、実装、テスト、保守運用まで一気通貫で支援しています。

モバイルバージョンを終了