」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 重構 ReadmeGenie

重構 ReadmeGenie

發佈於2024-12-23
瀏覽:248

Refactoring ReadmeGenie

介绍

本周我的任务是重构 ReadmeGenie。如果您刚刚来到这里,ReadmeGenie 是我的开源项目,它使用 AI 根据用户输入的文件生成自述文件。

最初,我的想法是,“该程序运行良好。从第一天起我就一直以有组织的方式开发它......那么为什么要改变它呢?”

好吧,在从该项目中休息一周后,我再次打开它并立即想到,“这是什么?”

为什么要重构?

为了给您一些背景信息,这里有一个例子:我曾经认为是完美的核心功能之一,结果证明比必要的要复杂得多。在重构过程中,我将其分解为五个独立的函数——你猜怎么着?现在代码更加清晰且更易于管理。

看一下这个函数的原始版本:

def generate_readme(file_paths, api_key, base_url, output_filename, token_usage):
    try:
        load_dotenv()

        # Check if the api_key was provided either as an environment variable or as an argument
        if not api_key and not get_env():
            logger.error(f"{Fore.RED}API key is required but not provided. Exiting.{Style.RESET_ALL}")
            sys.exit(1)

        # Concatenate content from multiple files
        file_content = ""
        try:
            for file_path in file_paths:
                with open(file_path, 'r') as file:
                    file_content  = file.read()   "\\n\\n"
        except FileNotFoundError as fnf_error:
            logger.error(f"{Fore.RED}File not found: {file_path}{Style.RESET_ALL}")
            sys.exit(1)

        # Get the base_url from arguments, environment, or use the default
        chosenModel = selectModel(base_url)
        try:
            if chosenModel == 'cohere':
                base_url = os.getenv("COHERE_BASE_URL", "https://api.cohere.ai/v1")
                response = cohereAPI(api_key, file_content)
                readme_content = response.generations[0].text.strip()   FOOTER_STRING
            else:
                base_url = os.getenv("GROQ_BASE_URL", "https://api.groq.com")
                response = groqAPI(api_key, base_url, file_content)
                readme_content = response.choices[0].message.content.strip()   FOOTER_STRING
        except AuthenticationError as auth_error:
            logger.error(f"{Fore.RED}Authentication failed: Invalid API key. Please check your API key and try again.{Style.RESET_ALL}")
            sys.exit(1)
        except Exception as api_error:
            logger.error(f"{Fore.RED}API request failed: {api_error}{Style.RESET_ALL}")
            sys.exit(1)

        # Process and save the generated README content
        if readme_content[0] != '*':
            readme_content = "\n".join(readme_content.split('\n')[1:])

        try:
            with open(output_filename, 'w') as output_file:
                output_file.write(readme_content)
            logger.info(f"README.md file generated and saved as {output_filename}")
            logger.warning(f"This is your file's content:\n{readme_content}")
        except IOError as io_error:
            logger.error(f"{Fore.RED}Failed to write to output file: {output_filename}. Error: {io_error}{Style.RESET_ALL}")
            sys.exit(1)

        # Save API key if needed
        if not get_env() and api_key is not None:
            logger.warning("Would you like to save your API key and base URL in a .env file for future use? [y/n]")
            answer = input()
            if answer.lower() == 'y':
                create_env(api_key, base_url, chosenModel)
        elif get_env():
            if chosenModel == 'cohere' and api_key != os.getenv("COHERE_API_KEY"):
                if api_key is not None:
                    logger.warning("Would you like to save this API Key? [y/n]")
                    answer = input()
                    if answer.lower() == 'y':
                        create_env(api_key, base_url, chosenModel)
            elif chosenModel == 'groq' and api_key != os.getenv("GROQ_API_KEY"):
                if api_key is not None:
                    logger.warning("Would you like to save this API Key? [y/n]")
                    answer = input()
                    if answer.lower() == 'y':
                        create_env(api_key, base_url, chosenModel)

        # Report token usage if the flag is set
        if token_usage:
            try:
                usage = response.usage
                logger.info(f"Token Usage Information: Prompt tokens: {usage.prompt_tokens}, Completion tokens: {usage.completion_tokens}, Total tokens: {usage.total_tokens}")
            except AttributeError:
                logger.warning(f"{Fore.YELLOW}Token usage information is not available for this response.{Style.RESET_ALL}")
        logger.info(f"{Fore.GREEN}File created successfully")
        sys.exit(0)

1。消除全局变量
全局变量可能会导致意想不到的副作用。将状态保持在其所属范围内,并在必要时显式传递值。

2.使用函数进行计算
尽可能避免将中间值存储在变量中。相反,在需要时使用函数执行计算 - 这使您的代码灵活且更易于调试。

3.不同的职责
单个函数应该做一件事,并且做得很好。将命令行参数解析、文件读取、AI 模型管理和输出生成等任务拆分为单独的函数或类。这种分离允许将来更轻松地进行测试和修改。

4。改进命名
有意义的变量和函数名称至关重要。一段时间后重新访问代码时,清晰的名称可以帮助您理解流程,而无需重新学习所有内容。

5。减少重复
如果您发现自己在复制和粘贴代码,则表明您可以从共享函数或类中受益。重复使得维护变得更加困难,小的变化很容易导致错误。

提交并推送到 GitHub

1。创建分支
我首先使用以下命令创建一个分支:

git checkout -b 

此命令创建一个新分支并切换到它。

2.进行一系列提交
一旦进入新分支,我就进行了增量提交。每次提交都代表一个逻辑工作块,无论是重构功能、修复错误还是添加新功能。频繁进行小额提交有助于更有效地跟踪更改,并更轻松地回顾项目的历史记录。

git status
git add 
git commit -m "Refactored function"

3.变基以保持干净的历史记录
在进行了几次提交之后,我重新调整了我的分支,以保持历史记录的干净和线性。变基允许我在将提交推送到 GitHub 之前对其进行重新排序、组合或修改。如果某些提交非常小或者我想避免太多增量更改使提交历史变得混乱,这尤其有用。

git rebase -i main

在这一步中,我在主分支之上启动了交互式变基。 -i 标志允许我以交互方式修改提交历史记录。我可以将一些较小的提交压缩为一个较大的、有凝聚力的提交。例如,如果我有一系列提交,例如:

重构第 1 部分
重构第 2 部分
修复重构中的错误

我可以将它们压缩成一个带有更清晰消息的提交

4。将更改推送到 GitHub
当我对 rebase 后的提交历史感到满意后,我将更改推送到 GitHub。如果您刚刚创建了一个新分支,则需要使用 -u 标志将其推送到远程存储库,该标志为将来的推送设置上游分支。

git push -u origin 

5。合并
在最后一步中,我快进合并到主分支并再次推送

git checkout main # change to the main branch
git merge --ff-only  # make a fast-forward merge
git push origin main # push to the main

要点

一切都有改进的空间。重构可能看起来很麻烦,但它通常会带来更干净、更易于维护和更高效的代码。因此,下次当您对重构感到犹豫时,请记住:总有更好的方法来做事。
尽管我认为现在已经很完美了,但我在下一次提交中肯定会有一些需要改进的地方。

版本聲明 本文轉載於:https://dev.to/htsagara/refactoring-readmegenie-4816?1如有侵犯,請洽[email protected]刪除
最新教學 更多>

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3