Cette semaine, j'ai été chargé de refactoriser le ReadmeGenie. Si vous venez d'arriver ici, ReadmeGenie est mon projet open source qui utilise l'IA pour générer des fichiers readme basés sur les fichiers saisis par l'utilisateur.
Au départ, mes pensées étaient : "Le programme fonctionne bien. Je l'ai développé de manière organisée depuis le premier jour... alors pourquoi le changer ?"
Eh bien, après avoir pris une pause d'une semaine dans le projet, je l'ai rouvert et j'ai immédiatement pensé : « Qu'est-ce que c'est ? »
Pour vous donner un peu de contexte, voici un exemple : une de mes fonctions principales, que je pensais autrefois parfaite, s'est avérée beaucoup plus complexe que nécessaire. Au cours du processus de refactoring, je l'ai divisé en cinq fonctions distinctes, et devinez quoi ? Le code est désormais beaucoup plus propre et plus facile à gérer.
Jetez un œil à la version originale de cette fonction :
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. Éliminer les variables globales
Les variables globales peuvent entraîner des effets secondaires inattendus. Conservez l'état dans la portée à laquelle il appartient et transmettez les valeurs explicitement si nécessaire.
2. Utiliser des fonctions pour les calculs
Évitez de stocker des valeurs intermédiaires dans des variables lorsque cela est possible. Utilisez plutôt des fonctions pour effectuer des calculs lorsque cela est nécessaire : cela permet à votre code de rester flexible et plus facile à déboguer.
3. Responsabilités distinctes
Une seule fonction doit faire une chose, et bien la faire. Divisez les tâches telles que l'analyse des arguments de ligne de commande, la lecture de fichiers, la gestion des modèles d'IA et la génération de sorties en fonctions ou classes distinctes. Cette séparation permet de faciliter les tests et les modifications à l'avenir.
4. Améliorer le nommage
Les noms de variables et de fonctions significatifs sont cruciaux. Lorsque vous revisitez votre code après un certain temps, des noms clairs vous aident à comprendre le flux sans avoir besoin de tout réapprendre.
5. Réduire la duplication
Si vous copiez et collez du code, c’est le signe que vous pourriez bénéficier de fonctions ou de classes partagées. La duplication rend la maintenance plus difficile et de petites modifications peuvent facilement entraîner des bugs.
1. Créer une branche
J'ai commencé par créer une branche en utilisant :
git checkout -b
Cette commande crée une nouvelle branche et y bascule.
2. Faire une série d'engagements
Une fois sur la nouvelle branche, j'ai effectué des commits incrémentiels. Chaque commit représente une partie logique du travail, qu'il s'agisse de refactoriser une fonction, de corriger un bug ou d'ajouter une nouvelle fonctionnalité. Effectuer de petits commits fréquents permet de suivre les modifications plus efficacement et facilite la révision de l'historique du projet.
git status git addgit commit -m "Refactored function"
3. Rebaser pour garder un historique propre
Après avoir effectué plusieurs commits, j'ai rebasé ma branche pour garder l'historique propre et linéaire. Le rebasage me permet de réorganiser, combiner ou modifier les commits avant qu'ils ne soient transmis à GitHub. Ceci est particulièrement utile si certains commits sont très petits ou si je veux éviter d'encombrer l'historique des commits avec trop de changements incrémentiels.
git rebase -i main
Dans cette étape, j'ai lancé un rebase interactif au-dessus de la branche principale. L'indicateur -i me permet de modifier l'historique des validations de manière interactive. Je pourrais regrouper certains de mes petits commits en un seul commit plus grand et cohérent. Par exemple, si j'avais une série de commits comme :
Refactoriser la partie 1
Refactoriser la partie 2
Correction d'un bug dans le refactor
Je pourrais les regrouper en un seul commit avec un message plus clair
4. Transférer les modifications vers GitHub
Une fois que j'ai été satisfait de l'historique des validations après le rebase, j'ai poussé les modifications vers GitHub. Si vous venez de créer une nouvelle branche, vous devrez la pousser vers le référentiel distant avec l'indicateur -u, qui définit la branche en amont pour les futurs push.
git push -u origin
5. Fusion
Lors de la dernière étape, j'ai effectué une fusion rapide vers la branche principale et j'ai poussé à nouveau
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
Tout peut être amélioré. La refactorisation peut sembler fastidieuse, mais elle aboutit souvent à un code plus propre, plus maintenable et plus efficace. Alors, la prochaine fois que vous hésiterez à refactoriser, rappelez-vous : il y a toujours une meilleure façon de faire les choses.
Même si je pense que c'est parfait maintenant, j'aurai certainement quelque chose à améliorer lors de mon prochain commit.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3