Valid XHTML     Valid CSS2    

DECRA : Décomposition, Conception et Réalisation d'Applications

Cours 5 : Solutions classiques aux problèmes classiques

Table des matières cliquable

  1. Un exemple classique : le couple login/password

  2. Des framework bienvenus : Django et ROR

  3. Le modèle MVC[2]

  4. Formats standards de fichiers

1. Un exemple classique : le couple login/password

Concevoir et développer des applications, ce n'est pas forcément concevoir et développer de nouveaux algorithmes, de nouvelles méthodes ou de de nouvelles solutions car beaucoup de composantes d'une application ont souvent déjà été programmées. Prenons l'exemple simple d'une application Web avec des utilisateurs qui doivent s'authentifier. Une technique classique aujourd'hui (2017) consiste à passer par un formulaire login/password avec souvent un login correspondant à une adresse mail.

 

          non su

Il n'y a rien de très difficile techniquement, mais il y a quand même pas mal de travail à effectuer (voir par exemple, nos pages LTE) :

  • il faut une créer puis administrer une base de données pour gérer les utilisateurs ;

  • il faut chiffrer les mots de passe à l'aide d'une fonction injective ;

  • il faut prévoir l'envoi de mail pour le fameux cas mot de passe oublié ;

  • il faut éventuellement prévoir de lister, comptabiliser, désactiver, réactiver, supprimer les utilisateurs...

Tout cela étant très standard, de nombreuses solutions ont déjà été créées et pour divers langages. S'il est possible de concevoir from scratch de nouvelles applications et d'inclure ces solutions dans l'application, des solutions logicielles nommées frameworks de programmation et frameworks de développement sont apparues, qui proposent d'aider à développer de nouvelles applications à partir de modules génériques, qu'elles soient Web ou pas. Pour plus de détails, nous renvoyons à notre cours de master sur ces frameworks et leurs liens avec les langages de scripts. Nous allons présenter brièvement ici deux fameux frameworks django et ror.

 

          non su          non su

2. Des framework bienvenus : Django et ROR

Les frameworks django et ror sont des ensembles cohérents de composants qui permettent facilement de réaliser des applications Web s'exécutant dans un navigateur. Ce ne sont pas des bibliothèques logicielles mais plutôt des modules génériques prêts à l'emploi qu'il faut configurer et combiner pour construire l'application. Nous n'en dirons pas plus car ces deux frameworks ont de nombreuses documentations, tutoriels et vidéos, comme le montrent les liens ci-dessous.

 

Type Rails Django
Tutoriel rails tutorial django tutorial
Vidéos video link 1 video link 2
Livres books link 1 books link 2

2.1 Un mini-mini-mini framework en PHP

Afin de montrer comment fonctionnent les frameworks, nous avons fait écrire par nos étudiants de master une commande nommée minifp qui crée, remplit et visualise une base de données MySQL. Voici le fonctionnement de cette commande :


      @janus~/Tmp|(~gH) > minifp --help
     
      Paramètres : --help | --model [optmodel | str ] --data optmodel | --view optview
     
       - le paramètre --help affiche cette aide
     
       - les options du paramètre --model sont tbl [ chmp:typ [chmp:typ]* | str ]
           ou tbl désigne la table,
                  chmp est un nom de champ,
                  typ est le type du champ (chaine ou entier)
                  str affiche la structure de la table
       - les options du paramètre --data sont tbl chmp:typ [chmp:typ]*
           ou chmp:typ est défini comme pour --model
       - les options de --view sont show URI | go URI | table tbl
           ou tbl désigne la table à visualiser.
     
     Rappel : ce programme n'est pas prévu pour une utilisation  dans une page Web.
     
     
     @janus~/Tmp|(~gH) > minifp --model exemple id:entier nom:chaine age:entier
      Table exemple créée  via le code MySql suivant
     
     @janus~/Tmp|(~gH) > minifp --model exemple passe:chaine
      Table exemple mise à jour  via le code MySql suivant
     
     @janus~/Tmp|(~gH) > minifp --data exemple id:1 nom:'"DUPOND"' age:20 passe:'"jxGDttg4w4e2Rsyso1Qdby4"'
      Valeurs id,  nom,  age,  passe   insérées dans la table exemple via le code MySql suivant
     
     @janus~/Tmp|(~gH) > minifp --data exemple id:2 nom:'"BOND"' age:30 passe:'""'
      Valeurs id,  nom,  age,  passe   insérées dans la table exemple via le code MySql suivant
     
     @janus~/Tmp|(~gH) > minifp --view exemple
      Valeurs de la table exemple :
     
     +------+--------+------+----------------------+
     | id   | nom    | age  | passe                |
     +------+--------+------+----------------------+
     |    1 | DUPOND |   20 | jxGDttg4w4e2Rsyso1Qd |
     |    2 | BOND   |   30 |                      |
     +------+--------+------+----------------------+
     

Il est clair qu'on ne voit nulle part de code MySQL et pourtant, la table est bien gérée. Il ne serait pas compliqué d'utiliser un formulaire HTML pour proposer et exécuter les actions de création remplissage et visualisation.

Avec un paramètre debug, il serait facile de voir le code MySQL produit par la commande, comme ci-dessous :


     @janus~/Tmp|(~gH) > minifp --model exemple id:entier nom:chaine age:entier
     
      Table exemple créée  via le code MySql suivant
      USE  test ;
      DROP TABLE IF EXISTS `exemple` ;
      CREATE TABLE `exemple` (
          id  int(5)  ,
          nom  varchar(20)  ,
          age  int(5)
      ) ;
     
     @janus~/Tmp|(~gH) > minifp --model exemple passe:chaine
     
      Table exemple mise à jour  via le code MySql suivant
      USE  test ;
      ALTER TABLE `exemple` ADD passe  varchar(20)  ;
     
     @janus~/Tmp|(~gH) > minifp --data exemple id:1 nom:'"DUPOND"' age:20 passe:'"jxGDttg4w4e2Rsyso1Qdby4"'
     
      Valeurs id,  nom,  age,  passe   insérées dans la table exemple via le code MySql suivant
      USE  test ;
      INSERT INTO `exemple` (
          id ,
          nom ,
          age ,
          passe
      ) VALUES (
          1 ,
          "DUPOND" ,
          20 ,
          "jxGDttg4w4e2Rsyso1Qdby4"
      )  ;
     
     @janus~/Tmp|(~gH) > minifp --data exemple id:2 nom:'"BOND"' age:30 passe:'""'
     
      Valeurs id,  nom,  age,  passe   insérées dans la table exemple via le code MySql suivant
      USE  test ;
      INSERT INTO `exemple` (
          id ,
          nom ,
          age ,
          passe
      ) VALUES (
          2 ,
          "BOND" ,
          30 ,
          ""
      )  ;
     
     @janus~/Tmp|(~gH) > minifp --view exemple
     
      Valeurs de la table exemple :
      mysql --host=localhost --user=anonymous --password=anonymous test -v -v -v
      SELECT * from exemple
     
     +------+--------+------+----------------------+
     | id   | nom    | age  | passe                |
     +------+--------+------+----------------------+
     |    1 | DUPOND |   20 | jxGDttg4w4e2Rsyso1Qd |
     |    2 | BOND   |   30 |                      |
     +------+--------+------+----------------------+
     
     2 rows in set (0.00 sec)
     

2.2 Un mini-mini exemple avec Django

Si tout est bien installé et configuré, une mini-version d'application peut-être créée via django-admin startproject loginp. Ensuite, les commandes suivantes permettent d'activer les bases de données, de définir un super-utilisateur et de lancer l'application, accessible à l'adresse http://127.0.0.1:8000, le système d'administration étant gérable à l'adresse http://127.0.0.1:8000/admin.


     ## python --version :  3.5.2 ; django-admin --version : 1.11.7 ; (gH) novembre 2017
     
     django-admin startproject loginp
     cd loginp/
     python3 manage.py migrate
     python3 manage.py createsuperuser
     # saisir les données, par exemple gh g@h.fr a1b2c3d4
     python3 manage.py runserver
     

non su

On peut éventuellement aller consulter les base de données générées avec sqlitebrower ou directement en sqlite3 si on en connait les commandes :


     (python3)  @ghchu5~/public_html/tests/mercredi/giluno|(~gH) > sqlite3 db.sqlite3
     
     SQLite version 3.11.0 2016-02-15 17:29:24
     Enter ".help" for usage hints.
     
     sqlite> .tables
     
     auth_group                  auth_user_user_permissions
     auth_group_permissions      django_admin_log
     auth_permission             django_content_type
     auth_user                   django_migrations
     auth_user_groups            django_session
     
     sqlite> .schema
     
     CREATE TABLE "django_migrations" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
                  "app" varchar(255) NOT NULL, "name" varchar(255) NOT NULL,
                  "applied" datetime NOT NULL);
     
     CREATE TABLE "auth_group" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
                  "name" varchar(80) NOT NULL UNIQUE);
     
     CREATE TABLE "auth_group_permissions" ("id" integer NOT NULL PRIMARY KEY
                   AUTOINCREMENT, "group_id" integer NOT NULL REFERENCES
                   "auth_group" ("id"), "permission_id" integer NOT NULL
                   REFERENCES "auth_permission" ("id"));
     
     [...]
     
     CREATE TABLE "auth_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
                  "password" varchar(128) NOT NULL, "last_login" datetime NULL,
                  "is_superuser" bool NOT NULL, "first_name" varchar(30) NOT NULL,
                  "last_name" varchar(30) NOT NULL, "email" varchar(254) NOT NULL,
                  "is_staff" bool NOT NULL, "is_active" bool NOT NULL,
                  "date_joined" datetime NOT NULL, "username" varchar(150) NOT NULL UNIQUE);
     
     CREATE TABLE "django_session" ("session_key" varchar(40) NOT NULL PRIMARY KEY,
                  "session_data" text NOT NULL, "expire_date" datetime NOT NULL);
     
     CREATE INDEX "django_session_expire_date_a5c62663" ON "django_session" ("expire_date");
     
     sqlite> select * from auth_user ;
     
     1|pbkdf2_sha256$36000$NssBMITyjy28$GVxNMcG20M7UUqazL+C/jxGDttg4w4e2Rsyso1Qdby4=|2017-11-08 13:29:02.960699|1|||g@h.fr|1|1|2017-11-08 13:27:37.708120|gh
     
     sqlite> .quit
     

Voici l'arborescence du projet créé :


     .
     +-- db.sqlite3
     +-- loginp
     |   +-- __init__.py
     |   +-- __pycache__
     |   |   +-- __init__.cpython-35.pyc
     |   |   +-- settings.cpython-35.pyc
     |   |   +-- urls.cpython-35.pyc
     |   |   +-- wsgi.cpython-35.pyc
     |   +-- settings.py
     |   +-- urls.py
     |   +-- wsgi.py
     +-- loginpDjango.zip
     +-- manage.py
     +-- tree_loginp.txt
     
     2 directories, 12 files
     

2.3 Un mini-mini exemple avec Ruby on rails

Si tout est bien installé et configuré, une mini-version d'application peut-être créée via rails new loginr. Ensuite, les commandes suivantes permettent de créer des utilisateurs avec un nom et un email, puis d'activer les bases de données et de lancer l'application, accessible à l'adresse http://127.0.0.1:3000, le système d'administration étant gérable à l'adresse http://127.0.0.1:3000/users.


     ## ruby --version : 2.4.2 ; rails --version : 5.1.4 ; (gH) novembre 2017
     
     rails  new loginr
     cd     loginr
     bundle install --without production
     bundle update
     spring stop     # si spring a déjà été lancé
     rails  generate scaffold User name:string email:string
     rails  db:migrate
     rails  server
     

Là encore, on peut éventuellement aller consulter les base de données générées avec sqlitebrower ou directement en sqlite3 si on en connait les commandes, la base de données est dans loginr/db/development.sqlite3, son schema en Ruby est schema.rb...

Voici l'arborescence du projet créé :


     .
     +-- app
     |   +-- assets
     |   |   +-- config
     |   |   |   +-- manifest.js
     |   |   +-- images
     |   |   +-- javascripts
     |   |   |   +-- application.js
     |   |   |   +-- cable.js
     |   |   |   +-- channels
     |   |   |   +-- users.coffee
     |   |   +-- stylesheets
     |   |       +-- application.css
     |   |       +-- scaffolds.scss
     |   |       +-- users.scss
     |   +-- channels
     |   |   +-- application_cable
     |   |       +-- channel.rb
     |   |       +-- connection.rb
     |   +-- controllers
     |   |   +-- application_controller.rb
     |   |   +-- concerns
     |   |   +-- users_controller.rb
     |   +-- helpers
     |   |   +-- application_helper.rb
     |   |   +-- users_helper.rb
     |   +-- jobs
     |   |   +-- application_job.rb
     |   +-- mailers
     |   |   +-- application_mailer.rb
     |   +-- models
     |   |   +-- application_record.rb
     |   |   +-- concerns
     |   |   +-- user.rb
     |   +-- views
     |       +-- layouts
     |       |   +-- application.html.erb
     |       |   +-- mailer.html.erb
     |       |   +-- mailer.text.erb
     |       +-- users
     |           +-- edit.html.erb
     |           +-- _form.html.erb
     |           +-- index.html.erb
     |           +-- index.json.jbuilder
     |           +-- new.html.erb
     |           +-- show.html.erb
     |           +-- show.json.jbuilder
     |           +-- _user.json.jbuilder
     +-- bin
     |   +-- bundle
     |   +-- rails
     |   +-- rake
     |   +-- setup
     |   +-- spring
     |   +-- update
     |   +-- yarn
     +-- config
     |   +-- application.rb
     |   +-- boot.rb
     |   +-- cable.yml
     |   +-- database.yml
     |   +-- environment.rb
     |   +-- environments
     |   |   +-- development.rb
     |   |   +-- production.rb
     |   |   +-- test.rb
     |   +-- initializers
     |   |   +-- application_controller_renderer.rb
     |   |   +-- assets.rb
     |   |   +-- backtrace_silencers.rb
     |   |   +-- cookies_serializer.rb
     |   |   +-- filter_parameter_logging.rb
     |   |   +-- inflections.rb
     |   |   +-- mime_types.rb
     |   |   +-- wrap_parameters.rb
     |   +-- locales
     |   |   +-- en.yml
     |   +-- puma.rb
     |   +-- routes.rb
     |   +-- secrets.yml
     |   +-- spring.rb
     +-- config.ru
     +-- db
     |   +-- development.sqlite3
     |   +-- migrate
     |   |   +-- 20171109125704_create_users.rb
     |   +-- schema.rb
     |   +-- seeds.rb
     +-- Gemfile
     +-- Gemfile.lock
     +-- lib
     |   +-- assets
     |   +-- tasks
     +-- log
     |   +-- development.log
     +-- package.json
     +-- public
     |   +-- 404.html
     |   +-- 422.html
     |   +-- 500.html
     |   +-- apple-touch-icon.png
     |   +-- apple-touch-icon-precomposed.png
     |   +-- favicon.ico
     |   +-- robots.txt
     +-- Rakefile
     +-- README.md
     +-- test
     |   +-- application_system_test_case.rb
     |   +-- controllers
     |   |   +-- users_controller_test.rb
     |   +-- fixtures
     |   |   +-- files
     |   |   +-- users.yml
     |   +-- helpers
     |   +-- integration
     |   +-- mailers
     |   +-- models
     |   |   +-- user_test.rb
     |   +-- system
     |   |   +-- users_test.rb
     |   +-- test_helper.rb
     +-- tmp
     +-- tree_loginr.txt
     +-- vendor
     
     42 directories, 81 files
     

Et le schéma (minimaliste) de la base de données :


     $gh>  cat loginr/db/schema.rb
     
     # This file is auto-generated from the current state of the database. Instead
     # of editing this file, please use the migrations feature of Active Record to
     # incrementally modify your database, and then regenerate this schema definition.
     #
     # Note that this schema.rb definition is the authoritative source for your
     # database schema. If you need to create the application database on another
     # system, you should be using db:schema:load, not running all the migrations
     # from scratch. The latter is a flawed and unsustainable approach (the more migrations
     # you'll amass, the slower it'll run and the greater likelihood for issues).
     #
     # It's strongly recommended that you check this file into your version control system.
     
     ActiveRecord::Schema.define(version: 2018_10_11_123129) do
     
       create_table "users", force: :cascade do |t|
         t.string "name"
         t.string "email"
         t.datetime "created_at", null: false
         t.datetime "updated_at", null: false
       end
     
     end
     

Il va sans dire que le paradigme d'ORM prend tout son sens ici, qu'on le décline en SQLAchemy pour Python/Django ou en ActiveRecord pour Ruby on Rails et que le test des sites Web associés est très bien automatisé comme le montrent les pages rails testing et django testing.

 

3. Le modèle MVC[2]

Le développement d'applications à l'aide d'un framework repose souvent sur le modèle MVC autrement dit modèle/vue/controleur. On pourra consulter la page outils_serveur pour plus d'informations sur les frameworks.

 

          non su

Remarque : pour les applications Web, il s'agit plus souvent d'un modèle dérivé de MVC2 plutôt que de MVC sachant que ces architectures logicielles étaient au début prévues pour des applications graphiques avant Internet. On pourra comparer ce type d'architecture à celle nommée trois tiers.

4. Formats standards de fichiers

Si les entrées/sorties des applications Web se réduisent souvent à des formulaires et à du texte formaté rendu via un navigateur, les applications classiques, elles, ont besoin de fichiers en entrée et en sortie. A part les formatages XML, il y a quelques standards assez simples à mettre en oeuvre pour que ces fichiers soient utilisables en bureautique. En particulier le format CSV est très pratique si les données doivent être traitées sous Microsoft Excel ou équivalent et le format RTF est sans doute un bon choix si les données doivent être traitées sous Microsoft Word, de même que le format PDF est le choix qui s'impose au fil des années pour les documents à imprimer.

XML PDF
CSV RTF

On n'oubliera pas ici que pandoc est une solution logicielle capable de convertir les différents formats textes de documents. En ce qui concerne les feuilles de tableurs et les bases de données relationnelles, les formats CSV et DLM suffisent amplement puisque l'information est écrite sous forme de tableaux rectangulaires contenant des données.

 

       retour au plan de cours  

 

Code-source PHP de cette page.

 

retour gH    Retour à la page principale de   (gH)