"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > ReadmeGenie 리팩토링

ReadmeGenie 리팩토링

2024년 12월 23일에 게시됨
검색:346

Refactoring ReadmeGenie

소개

이번 주에는 ReadmeGenie를 리팩터링하는 임무를 맡았습니다. 방금 여기에 도착하셨다면 ReadmeGenie는 AI를 사용하여 사용자가 입력한 파일을 기반으로 읽어보기를 생성하는 오픈 소스 프로젝트입니다.

처음에는 '프로그램이 잘 돌아가네요. 처음부터 체계적으로 개발해왔는데.. 그런데 왜 바꾸지?'라는 생각이 들었습니다.

글쎄, 일주일간 프로젝트를 쉬다가 다시 열어보니 '이게 뭐지?'라는 생각이 바로 들었습니다.

리팩토링하는 이유는 무엇입니까?

몇 가지 맥락을 설명하자면 다음과 같습니다. 한때 완벽하다고 생각했던 핵심 기능 중 하나가 필요 이상으로 훨씬 더 복잡한 것으로 나타났습니다. 리팩토링 과정에서 저는 이를 5개의 개별 기능으로 나누었습니다. 이제 코드가 훨씬 깔끔하고 관리하기 쉬워졌습니다.

이 함수의 원래 버전을 살펴보세요:

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에 변경 사항 푸시
리베이스 후 커밋 기록이 만족스러우면 변경 사항을 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에서 복제됩니다.1 침해 내용이 있는 경우, [email protected]으로 연락하여 삭제하시기 바랍니다.
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3