【授業レポート】システム開発(2年) 第38週目
〜エラーハンドリング徹底強化:失敗を制御する設計〜
第38週目は、先週の結合テストで露呈した多くの“バグ”と“例外”を題材に、
エラーハンドリング(例外処理・入力バリデーション・UI側のメッセージ設計) を体系的に学ぶ回となりました。
アプリが動くようになった今こそ、「どう壊れるかを設計する」ことが必要だと先生は強調しました。
■ 先生の導入:「エラーを放置するアプリは信頼されない」
田中先生:「上手く動くときだけ正しくてはダメ。
“失敗したときにどう振る舞うか”まで設計できて初めて、プロのシステムになります。」
先生は、先週の結合で出た代表的な失敗例を紹介:
- DB更新失敗 → 中途半端な状態になり在庫情報がおかしくなる
- 入力値エラーが UI に丸見え(例:ValueError の生テキスト)
- 例外がキャッチされずアプリごと停止
- 異常時のログが不足して原因追えず
これらを「今週の教材」として扱い、改善方法を学びました。
■ 今日の3本柱(テーマ)
- 入力バリデーション(UI層)
- 例外設計(Service層)
- 失敗の記録と通知(ログ&DAO層)
■ 実習①:入力バリデーションを UI で行う
アプリの多くのバグは “想定外の入力” が原因。
そこでまず UI層での防御 を徹底しました。
例:数値 ID が必要な場面
raw = input("Book ID: ")
if not raw.isdigit():
print("入力エラー:IDは数字で入力してください。")
return
book_id = int(raw)
生徒A:「数字チェックを入れただけでエラーが半分減った!」
バリデーションの原則(先生より)
- UIでできるだけ “機械的に弾く”
- ただし “業務的チェック” は Service でやる
- エラーメッセージは “ユーザーに理解できる言葉” で書く
■ 実習②:サービス層の例外設計(ドメイン例外とシステム例外の区別)
サービス層は業務ロジックを担当するため、
エラーも分類して扱うとコードが読みやすくなります。
例:ドメイン例外のクラスを作る
class BookNotFoundError(Exception):
pass
class BookNotAvailableError(Exception):
pass
サービス層での使い方
book = self.books_dao.get(book_id)
if not book:
raise BookNotFoundError()
if not book.is_available:
raise BookNotAvailableError()
UI層では、例外に応じて適切なメッセージを表示するよう整理。
生徒B:「例外に名前を付けるとエラーの意図が一気に分かりやすくなった!」
■ 実習③:DAO層での失敗制御とトランザクション管理
DAO層では次のような対策を実装:
- DB操作失敗時は 必ずロールバック
- DAO内部のSQLエラーはログへ(UIに出さない)
- トランザクション境界は Service で管理する
例:DAO内部の例外処理(学習用)
try:
cur.execute("UPDATE books SET is_available=%s WHERE id=%s", (flag, book_id))
self.conn.commit()
except Exception as e:
self.conn.rollback()
logger.error(f"DB Error: {e}")
raise
生徒C:「DAOでのロールバック忘れが原因の“在庫ズレ”バグが解消できた!」
■ 実習④:UI向けエラーメッセージのデザイン
UI側に “そのまま例外” を出すのはNG。
ユーザー向けの分かりやすい文言に変換する演習を行いました。
before(悪い例)
ValueError: invalid literal for int() with base 10
after(改善)
入力エラー:本IDは数字で入力してください。
学習ポイント
- “何が悪いか” を具体的に
- ユーザーに責任転嫁する表現は避ける
- 再入力方法を示すと親切
■ 実習⑤:ログ(アプリ内部向け)と UI(ユーザー向け)の役割分担を明確にする
先生はホワイトボードに大きく次の式を書きました:
**ログは開発者のため
エラー表示はユーザーのため**
その上で、次の2段階処理を推奨:
- Service or DAO で詳細をログへ書く(内部用)
- UI では簡潔で優しいメッセージを表示(外部用)
生徒D:「ログに“どのIDで失敗したか”が残ってると、調査がすごく楽!」
■ プチ演習:エラーパターンを10種類書き出す
班ごとに以下のカテゴリでエラーを列挙し、どの層で処理すべきか整理しました:
- 入力エラー
- 権限エラー
- 業務ロジックエラー
- DAOの整合性エラー
- 外部APIの失敗
- トランザクション失敗
- 予期しない例外(フォールバックを考える)
生徒E:「分類すると“どこで捕まえるべきか”が答えやすくなる!」
■ 先生のまとめのひとこと
「エラー処理は“安全装置”です。
ユーザーとデータを守る最終防衛ラインとも言えます。
正しく動くコードより、
“間違っても壊れないコード”の方が価値が高い。
今日学んだ設計は、今後の大きな開発やチーム開発で必ず役に立ちます。」
■ 宿題(来週の実装仕上げに向けて)
- 班で “主要ユースケースのエラー一覧表” を作成
- UI向けの 改善済みエラーメッセージ10種類 をまとめる
- 今日修正したエラーハンドリング部分の ミニ結合テストレポート を提出
■ 来週の予告:ユースケース完成&ミニ発表会
次週は、強化したエラーハンドリングを含め、
ユースケース単位での“完成形デモ” を行います。
アプリがどれだけ安定して動くかを披露する回です。
エラーと向き合い、
“壊れないアプリ”へ大きく前進した第38週目。
生徒たちは実装者としての視点だけでなく、
“ユーザーの安心” を設計する力も身につけ始めています。
