Esta semana recebi a tarefa de refatorar o ReadmeGenie. Se você acabou de chegar aqui, ReadmeGenie é meu projeto de código aberto que usa IA para gerar leia-mes com base nos arquivos inseridos pelo usuário.
Inicialmente, meus pensamentos eram: "O programa está funcionando bem. Tenho desenvolvido ele de forma organizada desde o primeiro dia... então por que mudá-lo?"
Bem, depois de uma pausa de uma semana no projeto, abri-o novamente e imediatamente pensei: "O que é isso?"
Para contextualizar, aqui está um exemplo: uma de minhas funções principais, que antes considerava perfeita, acabou se revelando muito mais complexa do que o necessário. Durante o processo de refatoração, dividi-o em cinco funções distintas – e adivinhe? O código está muito mais limpo e fácil de gerenciar agora.
Dê uma olhada na versão original desta função:
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. Elimine variáveis globais
Variáveis globais podem levar a efeitos colaterais inesperados. Mantenha o estado dentro do escopo ao qual ele pertence e passe valores explicitamente quando necessário.
2. Use funções para cálculos
Evite armazenar valores intermediários em variáveis sempre que possível. Em vez disso, use funções para realizar cálculos quando necessário – isso mantém seu código flexível e mais fácil de depurar.
3. Responsabilidades Separadas
Uma única função deve fazer uma coisa e fazê-la bem. Divida tarefas como análise de argumentos de linha de comando, leitura de arquivos, gerenciamento de modelo de IA e geração de saída em funções ou classes separadas. Essa separação permite testes e modificações mais fáceis no futuro.
4. Melhorar a nomenclatura
Nomes significativos de variáveis e funções são cruciais. Ao revisitar seu código depois de algum tempo, nomes claros ajudam você a entender o fluxo sem a necessidade de reaprender tudo.
5. Reduza a duplicação
Se você estiver copiando e colando código, é um sinal de que você pode se beneficiar de funções ou classes compartilhadas. A duplicação dificulta a manutenção e pequenas alterações podem facilmente resultar em bugs.
1. Crie uma filial
Comecei criando um branch usando:
git checkout -b
Este comando cria um novo branch e alterna para ele.
2. Fazendo uma série de commits
Uma vez no novo branch, fiz commits incrementais. Cada commit representa uma parte lógica do trabalho, seja refatorar uma função, corrigir um bug ou adicionar um novo recurso. Fazer commits pequenos e frequentes ajuda a rastrear as alterações de forma mais eficaz e facilita a revisão do histórico do projeto.
git status git addgit commit -m "Refactored function"
3. Rebaseando para manter um histórico limpo
Depois de fazer vários commits, reformulei meu branch para manter o histórico limpo e linear. O rebase me permite reordenar, combinar ou modificar commits antes de serem enviados ao GitHub. Isso é especialmente útil se alguns dos commits forem muito pequenos ou se eu quiser evitar sobrecarregar o histórico de commits com muitas alterações incrementais.
git rebase -i main
Nesta etapa, iniciei um rebase interativo no topo do branch principal. O sinalizador -i me permite modificar o histórico de commits de forma interativa. Eu poderia compactar alguns dos meus commits menores em um commit maior e coeso. Por exemplo, se eu tivesse uma série de commits como:
Refatorar parte 1
Refatorar parte 2
Corrigir bug no refatorador
Eu poderia comprimi-los em um único commit com uma mensagem mais clara
4. Enviando alterações para GitHub
Quando fiquei satisfeito com o histórico de commits após o rebase, enviei as alterações para o GitHub. Se você acabou de criar um novo branch, você precisará enviá-lo para o repositório remoto com o sinalizador -u, que define o branch upstream para pushes futuros.
git push -u origin
5. Mesclando
Na última etapa, fiz um fast-forward merge para o branch principal e pressionei novamente
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
Tudo tem espaço para melhorar. A refatoração pode parecer um incômodo, mas geralmente resulta em um código mais limpo, mais sustentável e mais eficiente. Portanto, da próxima vez que você hesitar em refatorar, lembre-se: sempre há uma maneira melhor de fazer as coisas.
Mesmo que eu ache que está perfeito agora, com certeza terei algo para melhorar no meu próximo commit.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3