0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アーキテクチャを明確にしたらAIが出力したコードの間違いを気づけるようになった

0
Posted at

ラビンです。
アーキテクチャ(システムの全体像)を実際に学び、個人開発に活かしたところ、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のコードを判断する基準として「設計をする力」が大事
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?