ラビンです。
アーキテクチャ(システムの全体像)を実際に学び、個人開発に活かしたところ、AIが出力したコードの間違いに気づけました。
AI駆動開発が当たり前の時代で求められるスキルである「設計をする力」の恩恵を肌で実感したので、実際に記事にしたいと思いました。
対象読者
-
私自身のみです
私が執筆している記事は、エンジニア1年未満気づきを発信しているだけです。間違っている可能性があるため、エンタメ程度で記事を読んでくれれば幸いです。
また、間違っているところがありましたら適当にコメントお願いします。
発端
3層アーキテクチャの真ん中部分になる「アプリケーション層」の内部にある、データアクセス層のコードを見ていたときのことです。
私のアプリでは、アプリケーション層(API)の中をさらに3つの層に分けています。
| 層 | ディレクトリ | 役割 |
|---|---|---|
| プレゼンテーション層 | routers/ |
リクエストを受け取り、レスポンスを返す |
| ビジネスロジック層 | services/ |
「重複していたら登録しない」などのルールを判断する |
| データアクセス層 | crud/ |
データベースを探す・保存するだけ |
routers/ → services/ → crud/ → MySQL
このうち、crud/の中にある退勤を記録する関数が、次のようなコードでした。
# crud/attendance.py
def stamp_clock_out(db, attendance_record):
# 今日の出勤記録を探す
data_base = db.query(AttendanceRecords).filter(...).first()
# もし出勤記録が見つかったら、退勤時間を上書き保存する
if data_base and data_base.start_time:
data_base.end_time = attendance_record.end_time
db.commit()
return data_base
return None
一見すると、普通に動くコードです。
しかし、crud/は「データベースを探す・保存するだけ」と決めていたので、
「もし出勤記録が見つかったら」という判断は、crudの仕事じゃなくない?
と違和感を覚えました。
何がおかしかったのか
「出勤記録があるときだけ退勤を記録できる」というのは、データベースの操作ではなく、アプリのルールです。
ルールの判断は、ビジネスロジック層(services/)の役割です。
つまり、このコードはデータアクセス層にビジネスロジックが混ざっている状態でした。
混ざっていると、例えば次のようなことが起こります。
- 「退勤のルールを変えたい」ときに、
services/とcrud/のどちらを見ればいいかわからない - 退勤できなかったことを
Noneで返しているため、呼び出し元が「なぜ失敗したのか」を判断できない
どう直したか
「探す」「保存する」はcrudに残し、「出勤記録がなければ退勤できない」というルールをservicesに移しました。
# crud/attendance.py:探す・保存するだけ
def get_attendance_by_date(db, member_id, date):
return db.query(AttendanceRecords).filter(...).first()
def update_clock_out(db, attendance, end_time):
attendance.end_time = end_time
db.commit()
return attendance
# services/attendance_service.py:ルールを判断する
def clock_out(db, attendance_record):
attendance = attendance_crud.get_attendance_by_date(db, attendance_record.member_id, attendance_record.date)
# 出勤記録がなければ退勤できない
if attendance is None:
raise AttendanceNotFoundError()
return attendance_crud.update_clock_out(db, attendance, attendance_record.end_time)
これで、crud/は本当に「探す・保存する」だけになりました。
なぜ気づけたのか
振り返ってみると、気づけた理由はアーキテクチャで各層の役割を明確に決めていたからだと思います。
もし役割を決めていなかったら、あのif文はただの「普通のコード」に見えて、違和感はなかったはずです。
「crudはデータベースを探す・保存するだけ」という判断の基準があったからこそ、そこからはみ出しているコードに気づけました。
AIはコードを書くのが得意ですが、そのコードが「どの層に書くべきものか」までは、こちらが決めた設計を知らなければ判断できません。
設計を決めておくことで、AIが出力したコードをレビューする基準を持てる、というのが今回の一番の学びです。
まとめ
- アプリケーション層の中も、プレゼンテーション層・ビジネスロジック層・データアクセス層に分けられる
- 「もし〜だったら」というルールの判断は、データアクセス層ではなくビジネスロジック層に書く
- 各層の役割を決めておくと、役割からはみ出したコードに自分で気づける
- AI駆動開発の時代こそ、AIのコードを判断する基準として「設計をする力」が大事