SRP: Stratégie de Résolution de Problème

Version du document: 1.2 (beta)

Disclaimer

Ce document est une proposition de stratégie permettant de résoudre, à l'aide d'un langage de programmation (comme Python), un problème exprimé en français comme vous en rencontrez dans un énoncé d'épreuve regroupée du cours ALP. Chacune et chacun y trouvera des outils utiles en cas de blocage face à la globalité d'une tâche complexe, énoncée en bloc. Comment commencer? Comment s'y prendre? Comment s'organiser? Quelles questions (se) poser? etc. Autant de questions pour lesquelles vous trouverez peut-être une réponse ici.

Introduction

Vous venez de recevoir l'énoncé du problème, il est là, sous vos yeux et n'attend plus qu'à être décortiqué afin que vous puissiez faire état des compétences acquises en cours de programmation... Comment commencer? Suivez le guide.

Etape no 1: Mettre en place

Lisez une première fois l'énoncé en entier, sans prendre de notes, sans surligner, sans trop réfléchir, puis...

armez-vous de 3 stylos surligneurs:

  • un jaune pour les éléments aidants à comprendre la problématique.
  • un rose pour les éléments qui donnent des pistes pour résoudre le problème (conseils des profs).
  • un bleu pour les parties qui peuvent se traduire directement en code source (signatures de fonctions, variables, etc.)

Relisez l'énoncé en surlignant à l'aide de vos stylos les différents éléments, selon la description de chaque couleur ci-dessus (vous pouvez, bien sûr choisir des couleurs différentes).

Etape no 2: Comprendre

Maintenant, l'idée est de comprendre le travail que vous devez dournir. La tâche n'est pas toujours évidente. Notamment, il s'agit de savoir rester simple en prenant les mots de l'énoncé dans leur sens premier, sans interpréstation. Par ailleurs, il est criucial que vous résistiez à la tentation de commencer à résoudre le problème ou une de ses parties avant d'avoir tout lu et complètement compris la tâche qui vous incombe.

Ainsi, pour cette étape, votre unique but est de reformuler le travail qui vous est demandé, et c'est tout! (c'est déjà un grand pas).

Nous vous proposons donc ici de:

  • vous munir d'une feuille de brouillon et d'un crayon et d'y saisir le titre "travail"
  • écrire, en-dessous, une phrase avec vos propres mots qui définit ce que l'énoncé de la question demande comme travail (que doit produire le code que vous devez écrire? Selon quelles contraintes?).
  • Si le point précédent pose un problème, interrogez alors un enseignant pour qu'il clarifie ce qui est attendu.

Etape no 3: Structurer (dessiner un plan)

Cette étape est très importante et vous propose de jouer à l'architecte. Entrez dans la peau d'un architecte responsable de créer les plans d'un programme qui produira le résultat compris lors de l'étape 2 (ou d'une maison).

Vous allez maintenant envisager les éléments nécessaires à la résolution du problème et voir comment ceux-ci peuvent s'imbriquer.

Par quoi commencer?`

Nous vous proposons de partir du point d'entrée du programme, c'est à dire de la première ligne du "main".

le main, ce mandateur

Les lignes de codes du main vont contenir des appels de fonctions, comme un architecte pourrait mandater des corps de métiers (maçons, couvreurs, careleurs, jardiniers, banquiers, etc) pour qu'ils produisent un élément du résultat global (le mur d'une maison par exemple) et éventuellement retournent un résultat (des banquiers qui répondent si oui ou non le projet est finançable avec un budget donné par exemple).

Comment s'y prendre?

Tout d'abord, il est intéressant de reprendre l'énoncé et de repérer les éléments surlignés en rose. En effet, dans les cours et les épreuves regroupées de l'ESIG, les énoncés contiennent systématiquement des éléments vous proposant un début de structure (fonctions proposées ou existantes dans un fichier source fourni), utilisez donc ces conseils.

Ensuite, demandez-vous par quoi va commencer votre programme: Par exemple s'il s'agit d'une entrée utilisateur, vous allez alors créer une variable pour l'enregistrer et lui attribuer une valeur en utilisant une fonction d'input. Puis, que va devenir cette valeur? va-t-elle être transmise à une fonction comme paramètre effectif? le résultat de cette fonction sera-t-il récupéré dans le main (via un return) puis ré-envoyé à une autre fonction pour générer un calcul, ou à une autre pour être affiché? A vous de le dire.

Pour la suite du programme, à vous d'imaginer les fonctions nécessaires. Ces fonctions peuvent être:

  • des fonctions de calcul qui retournent un résultat numérique (une somme, une moyenne, un maximum, un minimum ou un calcul mathématique).
  • des fonctions de traitement de chaînes de caractère qui retournent une String construite ou un caractère.
  • des fonctions de traitement de listes ou de dictionnaire qui retournent soit un résultat unique, soit une liste construite, ou un dictionnaire construit.
  • des fonctions de vérification qui retournent un résultat booléen (True ou False). Est-ce vrai? Est-ce valide? Est-ce possible? etc.
  • des fonctions d'affichage qui devraient être appelées procédures puisqu'elles ne retournent rien. Souvent elles s'occupent d'afficher un résultat sur la sortie (print).

NB: Ces fonctions utiliseront en entrée des valeurs reçues via des paramètres. Par ailleurs, l'utilisation de print n'est pas réservé aux fonctions d'affichage. Par exemple, une fonction de vérification de validité peut, avant de retourner False peut afficher un message d'erreur sur la sortie pour indiquer à l'utilisateur pourquoi le résultat n'est pas valide.

Des rectangles!

Nous vous proposons de dessiner des rectangles qui représentent les éléments de votre programme (des fonctions ou le main, en gros). Le premier rectangle est le main, listez-y les premières variables qu'il doit contenir (s'il en manque, elles viendront plus tard...) ainsi que les appels de fonctions. Voyez ces appels de fonctions comme la délégation d'une tâche à un corps de métier:

Depuis le main:"Construisez-moi un mur de 2 mêtres de large par 2.5 mètres de haut, fait de briques en béton et renvoyez-moi le poids total des briques une fois que votre travail sera effectué"

Dans cet exemple, le main contiendrait une variable poidsTotal dont la valeur serait initialisée à l'aide de l'appel de la fonction construireMur() (qui contiendra donc nécessairement un return)

poidsTotal = construireMur(2, 2.5, "béton")

Il s'agira ensuite de dessinner un rectangle pour la fonction construireMur, dans lequel on notera les paramètres (largeur, hauteur, typeBriques) ainsi que le return poidsTotal, mais SANS S'INTERESSER AU MONTAGE DU MUR nous reviendrons sur le comment faire plus tard (comment implémenter l'algorithme, en terme de programmation...), mais là, nous restons dans le rôle de l'architecte.

Puis, dessinez tous les rectangles que vous pouvez à l'aide de votre énoncé surligné, de votre imagination et aussi de votre expérience: Quels liens pouvez-vous faire avec des exercices passés, quelles fonctions (rectangles) avaient alors été créés? Est-ce applicable dans ce cas?

Rappelez-vous qu'il est souvent (tout le temps?) pertinent de considérer qu'une fonction (un rectangle) effectue une seule tâche. Par ailleurs, puisqu'elle effectue une tâche, il est alors possible (indispensable?) que son nom commence par un verbe d'action (affiche_blablabla, trouve_blablabla, calcule_blablabla, desine_blablabla, etc.). Prenez le temps de bien nommer vos fonctions, des noms adaptés aident à clarifier votre pensée alors que des noms trouvés à la va-vite vont provoquer de la confusion dans votre esprit (sans parler de celui de l'enseignant ou de vos futurs collaborateurs).

Finalement, essayez de définir les liens entre les rectangles (fonctions): qui appelle qui? Qu'est-ce qui est retourné? dessinez alors des flèches entre les rectangles.

Etape no 4: Coder

Enfin!!! Vous avez passé un sacré moment à créer votre plan et vous verrez que cela vaut la peine. Vous pouvez commencer à écrire du code! Félicitations, vous pouvez vous pencher sereinement sur l'implémentation de chaque rectangle (le "comment"), sans vous soucier du problème global (quel soulagement!).

Vous pouvez coder en confiance puisque chaque rectangle (fonction) est sensé(e) être indépendant(e) des autres rectangles (fonctions).

Peut-être, remarquerez-vous en codant la fonction construireMur qu'il manque quelquechose pour résoudre le problème et reviendrez alors sur votre architecture (les dessins de vos rectangles), celà n'est pas un problème et est même plutôt courant.

Rappel important: N'oubliez pas que chaque rectangle (fonction) est délimité(e) par des frontières (des traits) étanches... C'est-à-dire que les variables utilisées n'appartiennent qu'à ce rectangle et ne sont pas utilisables (ou modifiables) depuis l'extérieur. Le seul moyen (ou presque... mais ce n'est pas intéressant pour vous pour le moment) de faire passer des données d'un rectangle à un autre est d'utiliser des paramètres (appelés effectifs lors de l'appel d'une fonction) ou lorsqu'un rectangle (fonction) contient un return, alors l'appel de la fonction se transforme en le résultat de la fonction (ce qu'il y a après le return).

Etape no 5: Tester et débugger

Exécutez maintenant votre main et comparez vos sorties (votre maison) aux sorties produites de l'énoncé:

  • sont-elles cohérentes? (avec chaques données en entrée différente?)
  • sont-elles exactes?

Si vous pouvez répondre oui aux deux questions ci-dessus, alors c'est terminé. Cependant, vous répondrez probablement (...à coup sûr) "non" en cours de route, il s'agit alors de débugger votre programme. Ici, nous vous conseillons de mettre un point d'arrêt à l'appel de la première fonction dans le main, puis de suivre ce que l'interpréteur Python traverse lorsqu'il exécute votre programme (soyez attentif-ve-s aux valeurs des variables, des paramètres, etc...inspéctez-les... votre IDE favori vous aidera dans cette tâche.). En suivant le fil, ligne par ligne, variable par variable, paramètre par paramètre (et en lisant attentivement les éventuels messages d'erreurs), vous serez en mesure de comprendre pourquoi votre code ne produit pas le résultat attendu (mais une maison biscornue ou pas de maison du tout mais un message d'erreur...) et de corriger les lignes concernées.

Etape no 6: En cas de blocage, Resez stratégique

Ici, nous partons du principe que vous êtes en situation d'épreuve et que la gestion du temps implique aussi une certaine stratégie.

Ainsi, si vous ne parvenez pas au résultat parfait (ou pas du tout), regardez ce que vous pouvez produire dans votre code pour obtenir le maximum de points dans l'état, par exemple:

  • une fonction d'affichage est-elle indiquée dans le problème? (elles sont souvent facile à écrire et ramènent quelques points)
  • Un algorithme connu est-il reconnaissable? (un maximum, une somme, une moyenne pondérée, etc.)... il serait donc sûrement utile d'en intégrer un dans une fonction de calcul... N'oubliez pas de nommer vos variables et paramètres de manière cohérente avec le problème traité (lorsque vous récupérez du code provenant d'exercices tiers)
  • des commentaires dans le code sont sûrement nécessaires pour préciser votre intention, ajoutez-les!

Ayez aussi un oeil sur la montre... combien de questions restent à traiter?, combien de temps avez-vous encore à disposition? Ne restez pas bloqué-e trop longtemps sur une question algorithmique. Paufinez votre architecture, clarifiez-là, clarifiez vos intentions et passez à la suite.

-- NB: tous vos commentaires sont les bienvenus sur mon email: edu-servettazt@eduge.ch