Réponse au prompt “Quels refactoring suggères-tu pour que le code soit mieux structuré ?”

codex

26 mai 2026

Je suggérerais ces refactorings, dans cet ordre.

1. Séparer le moteur Logo de l’affichage

Aujourd’hui, les instructions modifient directement l’état global de turtle.

Par exemple Move.cpp calcule la nouvelle position puis appelle turtle::drawLine(). Ça mélange : - logique Logo ; - état de la tortue ; - rendu SFML ; - export SVG.

Le mieux serait d’avoir une classe TurtleState ou DrawingContext indépendante de SFML :

class TurtleState {
  double x;
  double y;
  double direction;
  bool penDown;
  std::vector<Line> lines;
};

Puis SFML et SVG ne feraient qu’afficher/exporter les lignes produites.

2. Supprimer les variables globales de Turtle.cpp

Actuellement, turtleX, turtleY, turtleDir, turtlePenDown, lines, window, etc. sont globaux.

C’est simple, mais ça rend le programme difficile à tester et à faire évoluer. Une classe TurtleRenderer ou SfmlTurtleView permettrait de mieux contrôler le cycle de vie.

3. Clarifier la responsabilité de Program

Program.cpp fait beaucoup de choses : - parse le programme principal ; - parse les fonctions ; - parse les blocs repete; - construit les instructions.

À terme, je créerais un vrai Parser, distinct de Program.

Program deviendrait juste un conteneur d’instructions et de fonctions, tandis que Parser serait responsable de lire les tokens.

4. Rendre l’exécution moins dépendante des iterators

L’exécution repose sur des InstructionList::iterator. Ça marche, mais c’est fragile dès qu’on veut déplacer, copier ou sérialiser des programmes.

Une alternative plus simple à maintenir : - stocker un index d’instruction courant (size_t currentIndex) ; - garder un pointeur/référence vers le Program courant ; - représenter un contexte par { Program*, index }.

Ce serait aussi plus facile à déboguer.

5. Améliorer les erreurs de parsing

ParseError dépend d’un iterator vers un token. Quand l’erreur arrive en fin de fichier, certains chemins peuvent être fragiles.

Le lexer pourrait produire des tokens avec position :

struct Token {
  TokenType type;
  std::string text;
  int line;
  int column;
};

Les messages deviendraient beaucoup plus utiles : Erreur ligne 4, colonne 12 : nombre attendu après avance.

6. Ajouter une validation des appels de fonction

Actuellement, un appel à une fonction inexistante peut finir en crash dans FunctionCall.cpp.

Il faudrait soit : - vérifier l’existence au parsing ; - soit lever une erreur claire à l’exécution.

7. Encapsuler les blocs de contrôle

FunctionCall et Repeat utilisent tous les deux la pile d’exécution. On pourrait créer une abstraction plus claire pour les instructions qui ouvrent un sous-programme.

Pas forcément à faire tout de suite, mais utile si tu ajoutes ensuite : - si; - tantque; - variables ; - paramètres de fonctions.

8. Ajouter des tests sans SFML

Comme le cœur du programme dépend de SFML, les tests sont compliqués. Après séparation moteur/rendu, tu pourrais tester :

et vérifier que le moteur produit 4 lignes formant un carré, sans ouvrir de fenêtre.

Le plus rentable à court terme : commencer par séparer TurtleState du rendu SFML/SVG. C’est le refactoring qui débloque presque tous les autres.