💬

2種類のAIにコード書かせる・レビューさせる・改善させする

2024/05/24に公開

概要

こちらが面白そうで、graphai向けだと思い試してみました

https://x.com/hAru_mAki_ch/status/1793271225646723481

graphaiとは

https://zenn.dev/singularity/articles/graphai-tutorial_1

"GraphAIとは、TypeScriptで書かれた単機能のAgentと呼ばれるプログラムを、YAMLやJSONファイルに書かれたデータフローグラフの法則に従って順次非同期に実行するプログラムのエンジンです。"

コード

https://gist.github.com/itouh2/aaed3c8e2718f3d9e1fb819af22a9880

graphaiで動かすにあたって変更点

元記事はAIの出力から、コードの部分を抜き出して次のプロンプトに渡すようですが、
プロンプトを変更して、出力をそのまま次のAgentに渡すようにしました

例:

別のAIに課題を提示し、コードと説明を生成してもらいました。
批評的にレビューし、以下の観点からリファクタリングの提案をお願いします。
1. コードの可読性と保守性
2. 命名規則と変数・関数名の適切さ
3. コードの構造とモジュール化
4. エラーハンドリングと例外処理
5. パフォーマンスと効率性
具体的な修正案とともに、フィードバックをお願いします。

別のAIが生成されたコードと説明はこちらです:
(前の出力を挿入)

graphai 流れ

  1. AIにコードを書いてもらう(output1)
  2. AIに批評してもらう(output2)
  3. さらに改善点がないか(output3)

output1 (AIにコードをまず書いてもらう)

以下に、要件を満たすPythonコードを提供します。コードは2つのモジュールに分かれています: file_utilities.pydisplay_utilities.py

file_utilities.py

# file_utilities.py

class FileManager:
    def __init__(self, file_name):
        self.file_name = file_name

    def read_file(self):
        """
        Reads the content of the file and returns it as a string.
        """
        try:
            with open(self.file_name, 'r') as file:
                return file.read()
        except FileNotFoundError:
            return f"Error: The file '{self.file_name}' was not found."
        except Exception as e:
            return f"An error occurred while reading the file: {e}"

display_utilities.py

# display_utilities.py

from file_utilities import FileManager

def display_contents_of_file(file_name):
    """
    Reads and displays the contents of the specified file.
    """
    file_manager = FileManager(file_name)
    content = file_manager.read_file()
    print(content)

# Example usage:
if __name__ == "__main__":
    file_name = 'example.log'  # Replace with your log file name
    display_contents_of_file(file_name)

説明

  1. file_utilities.py:

    • FileManagerクラスはコンストラクタでファイル名を受け取り、read_fileメソッドでファイルの内容を文字列として返します。
    • ファイルが見つからない場合や他の例外が発生した場合に適切なエラーメッセージを返します。
  2. display_utilities.py:

    • display_contents_of_fileメソッドはファイル名を受け取り、FileManagerクラスを使ってファイルの内容を読み取り、それをコンソールに出力します。
    • モジュールが直接実行された場合の例として、ファイル名を指定して内容を表示するコードも含めています。

拡張性と保守性

  • 各モジュールは単一責任の原則に従っており、ファイル操作と表示操作が明確に分離されています。
  • エラーハンドリングが含まれており、将来的にエラー処理を拡張する際にも対応しやすい設計となっています。
  • 必要に応じて、FileManagerクラスやdisplay_contents_of_fileメソッドを拡張することが容易です。

この設計はクリーンで保守性が高く、他の開発者が理解しやすいコードとなっています。

output2 (AIにコードに批評してもらう)

このコードは全体的に良く設計されており、きちんとモジュール化されていて可読性と保守性が高いです。ただし、いくつか改善できる点があります。

  1. コードの可読性と保守性:

    • FileManagerクラスのread_fileメソッドがファイルの読み込みだけでなく、エラーメッセージの生成も行っています。このように複数の責任を持つと、関数が複雑になり保守性が低下します。エラーハンドリングは呼び出し元で行い、このメソッドではファイルの読み込みだけを行うようにしましょう。
  2. 命名規則と変数・関数名の適切さ:

    • FileManagerという名前は一般的すぎます。このクラスが何をするのかより具体的に表現するために、TextFileReaderなどの名前に変更すると良いでしょう。
  3. コードの構造とモジュール化:

    • display_contents_of_file関数がファイルの読み込みと表示の両方を行っています。Single Responsibility Principleに従い、これらの操作を別の関数に分割しましょう。
  4. エラーハンドリングと例外処理:

    • 現状のコードはエラーメッセージを文字列として返していますが、これは適切ではありません。エラーが発生した場合は例外を発生させ、呼び出し元で適切に処理するようにしましょう。
  5. パフォーマンスと効率性:

    • 現状のコードでは大きな問題はありませんが、非常に大きなファイルを読む場合、メモリに全てをロードすると問題が発生する可能性があります。そのような場合は、ファイルをチャンクごとに読むなどの対策が必要です。ただし今回はその必要はないでしょう。

これらのフィードバックを元に、以下のようにリファクタリングを行います。

file_utilities.py

# file_utilities.py

class TextFileReader:
    def __init__(self, file_name):
        self.file_name = file_name

    def read_file(self):
        """
        Reads the content of the file and returns it as a string.
        """
        with open(self.file_name, 'r') as file:
            return file.read()

display_utilities.py

# display_utilities.py

from file_utilities import TextFileReader

def read_file_contents(file_name):
    """
    Reads the contents of the specified file.
    """
    file_reader = TextFileReader(file_name)
    return file_reader.read_file()

def display_text(text):
    """
    Displays the specified text.
    """
    print(text)

# Example usage:
if __name__ == "__main__":
    file_name = 'example.log'  # Replace with your log file name
    try:
        text = read_file_contents(file_name)
        display_text(text)
    except FileNotFoundError:
        print(f"Error: The file '{file_name}' was not found.")
    except Exception as e:
        print(f"An error occurred while reading the file: {e}")

このようにリファクタリングすることで、各関数の責任が明確になり、エラーハンドリングも適切に行えるようになります。

output3 (さらに改善点がないか)

フィードバックとリファクタリング案は非常に良い方向性を示していました。さらに改善点を追加し、コードをよりモジュール化し、可読性と保守性を向上させるためのリファクタリングを行います。

改善点

  1. エラーハンドリングの分離: read_fileメソッドでは例外を発生させ、呼び出し側で適切に処理するようにします。
  2. 命名規則の改善: より具体的なクラス名とメソッド名を使用します。
  3. コードの構造の改善: ファイルの読み込みと表示を別々の関数に分けることで、Single Responsibility Principleに従います。
  4. コメントの追加: コメントを日本語で追加し、コードの理解を助けます。

以下のリファクタリング案を示します。

file_utilities.py

# file_utilities.py

class TextFileReader:
    def __init__(self, file_name):
        self.file_name = file_name

    def read_file(self):
        """
        ファイルの内容を読み込んで文字列として返す。
        ファイルが存在しない場合やアクセスできない場合は例外を発生させる。
        """
        try:
            with open(self.file_name, 'r', encoding='utf-8') as file:
                return file.read()
        except FileNotFoundError:
            raise FileNotFoundError(f"ファイル '{self.file_name}' が見つかりません。")
        except Exception as e:
            raise Exception(f"ファイル '{self.file_name}' の読み込み中にエラーが発生しました: {e}")

display_utilities.py

# display_utilities.py

from file_utilities import TextFileReader

def read_file_contents(file_name):
    """
    指定されたファイルの内容を読み込む。
    """
    file_reader = TextFileReader(file_name)
    return file_reader.read_file()

def display_text(text):
    """
    指定されたテキストを表示する。
    """
    print(text)

def display_contents_of_file(file_name):
    """
    指定されたファイルの内容を読み込んで表示する。
    """
    try:
        text = read_file_contents(file_name)
        display_text(text)
    except FileNotFoundError as e:
        print(e)
    except Exception as e:
        print(f"ファイルの読み込み中にエラーが発生しました: {e}")

# 実行例:
if __name__ == "__main__":
    file_name = 'example.log'  # ログファイル名を指定
    display_contents_of_file(file_name)

改善点の説明

  1. エラーハンドリングの分離: read_fileメソッドは例外を発生させ、呼び出し元でエラーを処理するようにしました。
  2. 命名規則の改善: TextFileReaderというクラス名を使用し、メソッド名も明確にしました。
  3. コードの構造の改善: display_contents_of_file関数を追加し、ファイルの読み込みと表示を分けました。
  4. コメントの追加: 各メソッドと関数に日本語のコメントを追加し、コードの理解を助けました。

このようにすることで、コードの可読性と保守性が向上し、将来の拡張にも柔軟に対応できる設計となります。

Discussion