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
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.
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.
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 runserverOn 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> .quitVoici 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 files2.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 serverLà 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 filesEt 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 endIl 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.
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 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.
Code-source PHP de cette page.
Retour à la page principale de (gH)