UE5 : Fondamentaux du développement web frontal, niveau 2

Séance 7 : Bonnes pratiques de développement et rendu du devoir

  1. Propreté du code
    1. Commentaires
    2. Nommages
    3. Rangement
    4. Banir les chemins absolus
    5. Variabilisation
    6. Liens internes
  2. Gestion des erreurs
  3. Rendu du devoir
    1. Base de données
    2. Requirements
    3. README.md
    4. Dépôt du code
    5. Ce que je jouerai pour lancer votre application

Propreté du code

La propreté et la structure du code de l'application compte pour 5 points dans la note finale. Plusieurs normes et règles sont à respecter.

Commentaires

Que ce soit dans une route Flask, une classe d'un modèle SQLAlchemy, un template, du Javascript, etc., tout doit être commenté pour je puisse voir ce que telles lignes de code font et si vous avez compris votre propre code. Le commentaire de code est essentiel, pas seulement pour ce devoir: un code commenté est compréhensible par tous, et modifiable par tous.

Exemple de commentaires pour différents langages:

# itération sur la liste des pays et affichage des pays un à un
for un_pays in pays:
    print(pays)
// affichage de la variable i
console.log(i);
/* les balises span sont bleues */
span {
  color: blue;
}
<!-- Ceci est un paragraphe -->
<p>Un paragraphe</p>
-- sélection de tous les pays
SELECT *
FROM country a -- a est l'alias de country dans cette requête

Pour Python, un autre type de commentaire doit être présent: il s'agit de la documentation des classes et des fonctions, donc chaque fois qu'il y a un class ou un def dans le code. Prenons deux exemples:

class Users(UserMixin, db.Model):
    """
    Une classe représentant les utilisateurs. On indique ici une rapide description de la classe.

    Attributes
    ----------
    id : sqlalchemy.sql.schema.Column
        Identifiant de l'utilisateur. C'est la clé primaire. Cet attribut est une Column SQLALchemy.
    prenom : sqlalchemy.sql.schema.Column
        Prénom de l'utilisateur
    password : sqlalchemy.sql.schema.Column
        Mot de passé hashé de l'utilisateur
    mail : sqlalchemy.sql.schema.Column
        Adresse mail de l'utilisateur

    Methods
    -------
    identification(mail, password)
        Permet l'identification d'un utilisateur à partir d'un  mail et d'un mot de passe fournis
    """
    __tablename__ = "users"

    id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    prenom = db.Column(db.Text, nullable=False)
    password = db.Column(db.String(100), nullable=False)
    mail = db.Column(db.String(80), nullable=False)

    @staticmethod
    def identification(mail, password):
        """
        Permet l'identification d'un utilisateur à partir d'un  mail et d'un mot de passe fournis

        Les deux arguments sont obligatoires

        Parameters
        ----------
        mail : str, required
            Le mail fourni par le client
        password : str, required
            Le mot de passe fourni par le client

        Returns
        -------
        app.models.users.Users
            Une instance de la classe Users si l'identification est un succès, sinon retourne None
        """
        utilisateur = Users.query.filter(Users.mail == mail).first()
        if utilisateur and check_password_hash(utilisateur.password, password):
            return utilisateur
        return None
@app.route("/pays")
@app.route("/pays/<int:page>")
def pays(page=1):
    """
    Route permettant l'affichage des pays, avec une pagination possible

    Parameters
    ----------
    page : int, optional
        Le numéro de la page à afficher (si non fourni, 1 par défaut)

    Returns
    -------
    template
        Retourne le template pays.html
    """
    return render_template("pages/pays.html", 
        sous_titre="Pays", 
        donnees= Country.query.order_by(Country.name).paginate(page=page, per_page=app.config["PAYS_PER_PAGE"]))

Nommages

Les fichiers, les variables, les classes et les fonctions doivent être nommés de manière logique et compréhensible. Ils doivent porter le nom de ce qu'ils sont ou font vraiment.

Rangement

Les packages (par exemple routes ou templates) doivent être rangés en différents modules:

Banir les chemins absolus

Aucun chemin absolu ne doit se trouver dans l'application:

Le seul chemin absolu qu'il y aura est éventuellement un chemin absolu vers la base SQLite: il sera à indiquer dans le fichier .env.

Variabilisation

Toute valeur de configuration (comme le PER_PAGE de la pagination, des URL d'API, etc.) doit être sortie de l'application pour être mise en variable d'environnement (donc dans .env).

Liens internes

Comme vu en Séance2, les liens internes se font via url_for() dans les routes et les templates. L'écriture de ces liens en dur est à proscrire, le domaine et le port changent constamment.

Gestion des erreurs

La gestion des erreurs a été vue en Séance5; elle implique notamment:

Aucune erreur 4XX ou 5XX ne devra être retournée directement à l'utilisateur: une page indiquant qu'une erreur est survenue devra être retournée. C'était l'objet de l'exercice REF-1 de la Séance5.

Rendu du devoir

Base de données

Plusieurs solutions pour me fournir une base de données :

Dans tous les cas, si une base de données est adossée à l'application, il faudra me fournir le MRD (modèle relationnel de données) de la base de données correctement représenté.

Requirements

Le fichier requirements.txt, mis à la racine de l'application, est obligatoire. Il permet d'indiquer toutes les dépendances de l'application et leurs versions. Il est nécessaire pour pouvoir lancer l'application sur d'autres machines (dont la mienne pour la correction).

Pour le générer, se rendre à la racine de l'application (à côté du fichier run.py). Activer l'environnement virtuel.

Simplement exécuter la commande suivante: pip freeze > requirements.txt.

README.md

Le README est le fichier qui donne une première documentation de l'application. Il est présent à la racine de l'application. C'est ce fichier qui est rendu par Github quand on va sur un dépôt.

Pour le devoir, voici ce que le README doit indiquer:

Les instructions d'installation et de lancement de l'application doivent être le plus précises possibles, et sont pour la plupart évidentes. Il faut se mettre à la place d'une personne qui n'y connaît rien et qui doit installer puis lancer une application en Python. Des exemples d'étapes:

Dépôt du code

Le devoir sera obligatoirement rendu via un dépôt disponible sur Github, les cours de Git étant désormais passés. Aucune autre forme de rendu (.zip, etc.) ne sera accepté.

Note 1 : Il est fortement recommandé de développer l'application en utilisant Git et Github. C'est le moyen le plus viable et rapide de développer en groupe.

Note 2 : Déployer sur le cloud est optionnel et ne rentre pas en compte dans la note. Vous pouvez le faire par pur plaisir, ou pour vérifier que votre dépôt de code est correct et fonctionne bien.

Ne doivent pas être présents dans le dépôt les éléments suivants:

Vous trouverez un exemple de .gitignore ici

Ce que je jouerai pour lancer votre application

Voici toutes les étapes que je jouerai dans l'ordre pour lancer votre application. Je les indique ici pour que vous les testiez de votre côté avant de me rendre le devoir. Si ça ne fonctionne pas de votre côté, ça ne risque pas de fonctionner chez moi; ce n'est donc pas la peine de rendre le devoir.

On suppose que j'ai Python 3.6 installé sur ma machine Ubuntu 20.04 (ou plus).

  1. git clone lien_vers_le_depot.git
  2. cd depot/
  3. virtualenv env -p python3
  4. Installation de la base de données: posage du .sqlite à côté de run.py, ou installation d'un serveur
  5. Création du fichier .env à côté de run.py à partir des variables indiquées dans le README
  6. source env/bin/activate
  7. pip install -r requirements.txt
  8. python run.py