Sam & Max » framework http://sametmax.com Du code, du cul Sat, 07 Nov 2015 10:56:13 +0000 en-US hourly 1 http://wordpress.org/?v=4.1 The User is dead 18 http://sametmax.com/the-user-is-dead/ http://sametmax.com/the-user-is-dead/#comments Tue, 14 Jul 2015 12:27:42 +0000 http://sametmax.com/?p=16615 L’authentification de mémé (enfin, mémé…) n’a plus de sens, et pourtant, on continue de la montrer en exemple dans tous les tutos :

  • Un compte utilisateur.
  • Un email.
  • Un mot de passe.

Boom, on vérifie le mot de passe (avec un peu de chance sur une version sainement hachée), on identifie l’utilisateur, et c’est plié.

C’est simple, c’est beau, ça marche.

Mais ça ne représente pas du tout la réalité.

Une des plus grosses erreurs de design de frameworks comme Django est justement la classe User.

En soit, la classe User n’est pas un problème, mais son omniprésence dans toutes les couches du framework et sa promotion au rang d’unité de référence dans les apps tierces parties ont gardé la vision de l’authentification très monolithique.

C’est que le Web n’a plus du tout la forme qu’il avait il y a 10 ans, et aujourd’hui, vous pouvez vous connecter via un service (facebook, twitter, github…), utiliser une authentification à double facteur (sms, email, yubikey…) ou avoir un compte unique qui unifie plusieurs fournisseurs (ah, le fameux compte Google qui fait gmail, youtube, calendar, play, saucisseland…).

Les gens ont plusieurs identités, plusieurs comptes, plusieurs modes d’authentification, plusieurs points d’entrées. Ce modèle ne marche plus :

USER <-- Profile 

Si vous créez un service aujourd'hui et que vous souhaitez prendre en compte cette réalité, le schéma en base de données va plutôt ressembler à un truc du genre :

                      +-------+
                      |Session|
                      +----+--+
                           |
                           |
                           |
                           |
+-----------+         +----v---+         +--------+
|  Identity | <-------+ Account| <-------+Profile |
+-----------+         +--------+         +--------+
                 +------^   ^--------+
                 |                   |
                 |                   |
                 |                   |
                 |                   |
         +-------+-----+      +------+----+
         | Credential  |      |  Service  |
         +-------------+      +-----------+

Et encore, je n'ai pas mis les permissions, les devices, les comptes multi-utilisateurs, la vérification des comptes (lien email, sms, etc), les niveaux d'offre commerciale... Ca rend le truc vraiment compliqué.

Ce qui est important ici, c'est que la notion de compte devient centrale, mais que seule l'identité est unique. Une identité peut avoir plusieurs comptes. Et un compte peut être chez votre service ou un service externe. Et l'authentification peut très bien avoir lieu ailleurs : ldap, OAuth, Mozilla Personna, Open ID...

Si votre utilisateur a un compte chez Facebook et un compte chez vous, les deux sont des comptes, avec leurs profils, reliés à la même identité, servant à vous donner des informations, permettant de se loguer... Et vous devez garder une trace de tout ça. Le fait que l'API d'un service tape sur votre serveur et l'autre non n'a en fait aucune importance pour l'utilisateur, qui utilise tout ça comme un gros blob comme si internet était un tout.

La nouvelle génération ne fait pas la différence avec un site Web et un app, ne sait pas ce qu'est une URL ou un cookie et ne veut pas rentrer trop de mots de passe, mais veut par contre utiliser 5000 services.

Ainsi on voit que les archis basées sur des microservices (hello crossbar :)) commencent à avoir la côte, faisant abstraction de la notion de "ceci est mon app, ceci est ton app" dans la structure de son projet. Bien entendu, la distinction est importante d'un point de vue humain, mais du point de vue du workflow d'authentification, non.

Par contre, forcément, ça fait beaucoup plus qu'une table User et une table Profile en base de données, et c'est pourquoi toutes les apps pluggables des frameworks actuellement ont leurs propres structures bizarres, incompatibles et torturées pour faire tenir toute cette logique. Parce qu'on code sur des frameworks qui vivent encore dans les années 2000, qui passent à votre vue un objet User en paramètre avec ses attributs username et email.

Mais ce que vous avez en face de vous, ce n'est pas un utilisateur.

C'est une session d'utilisation.

D'un service (le votre). Liée à un compte. Qui peut-être (surement) possède un profil avec un username.

Cette session s'est initiée par une authentification avec une méthode parmi 100 auprès d'un service également, lié à un compte, avec un profil. Peut-être le même service que celui qui est utilisé, peut-être pas.

Et cette authentification a pu être demandée par un utilisateur, ou encore un autre service, ou un logiciel client complètement automatiquement. Souvenez-vous : la session n'a peut-être aucun humain derrière.

Ce qui est en face de vous n'est pas un utilisateur. L'utilisateur est mort il y a des années.

]]>
http://sametmax.com/the-user-is-dead/feed/ 18
Est-ce que “framework x” supporte la charge ? 16 http://sametmax.com/est-ce-que-framework-x-supporte-la-charge/ http://sametmax.com/est-ce-que-framework-x-supporte-la-charge/#comments Tue, 24 Dec 2013 21:08:05 +0000 http://sametmax.com/?p=7754 Oui.

]]>
http://sametmax.com/est-ce-que-framework-x-supporte-la-charge/feed/ 16
Le bonheur des frameworks 13 http://sametmax.com/le-bonheur-des-frameworks/ http://sametmax.com/le-bonheur-des-frameworks/#comments Mon, 17 Dec 2012 13:37:58 +0000 http://sametmax.com/?p=3709 Traduction un peu adaptée de l’article Why I hate framework de Joel Spolsky

J’ai voulu construire une petite étagère pour y ranger les condiments.

Ayant fait un peu de menuiserie avant, j’avais une bonne idée de ce dont j’avais besoin : un peu de bois et quelques outils de base. Un mètre, une scie, un niveau et un marteau.

D’ailleurs, si je voulais construire toute une maison, j’en aurais besoin également. Du coup je suis allé dans une quincaillerie, et j’ai demandé au vendeur où je pouvais trouver un marteau.

“- Un marteau ?”, me répondit-il. “Plus personne n’achète des marteaux de nos jours vous savez. Ils sont un peu vieux jeu.”

Surpris, je lui demande pourquoi.

– “Et bien, le problème avec les marteaux, c’est qu’il y en a plein de différents types. Des marteaux arrache-clou, des masses, des marteaux de tapissier… Que se passerait-il si vous achetiez un type de marteau et réalisiez que vous avez besoin d’un autre type plus tard ? Vous devriez achetez un autre marteau pour votre prochaine tâche. Il se trouve que la plupart des gens veulent vraiment un seul marteau qui peut être utilisé pour la majorité des tâches qu’ils peuvent rencontrer dans leur vie.”

– “Ça me parait logique. Pouvez-vous me dire où je peux trouver un marteau universel ?”

– “Non, nous ne les vendons plus. Ils sont obsolètes.”

– “Vraiment ? Je pensais que vous veniez de dire que le marteau universel était l’avenir.”

– “Il se trouve que, si vous faites un seul marteau qui puisse être utilisé pour toutes sortes de tâches, il n’est vraiment bon, à aucune d’entre elles. Enfoncer un clou avec une masse n’est pas très efficace. Et pour tuer votre petite amie, rien ne vaut un marteau de tapissier.”

– “C’est clair ! Donc, si plus personne n’achète des marteaux universels, et que vous ne vendez plus de marteaux à l’ancienne, quels marteaux vendez-vous ?”

– “En fait, nous n’en vendons pas.”

– “Alors…”

– “D’après nos recherches, ce dont les gens ont besoin n’est pas un marteau universel du tout. Il vaut toujours mieux avoir le bon marteau pour le bon boulot. Donc, nous avons commencé à vendre des fabriques de marteau, capable de produire n’importe quel marteau qui pourrait vous intéresser. Tout ce dont vous avez besoin est de remplir la fabrique de travailleurs, lancer la machinerie, acheter les matériaux de base, payer les charges et hop, vous avez *exactement* le type de marteau dont vous avez besoin en un clin d’œil.”

– “Mais je ne veux pas acheter une fabrique de marteaux…”

– “Parfait. Car nous n’en vendons plus.”

– “Attendez, vous venez de me dire que…”

– “Nous avons découvert que la plupart des gens n’ont pas besoin d’une fabrique complète de marteaux. Certains, par exemple, n’auront jamais besoin d’un marteau de tapissier. (Peut être qu’ils n’ont pas d’ex. Ou peut être qu’ils les ont tué avec des pics à glace.). Donc il n’y a aucune raison pour quelqu’un d’acheter une fabrique de marteaux pour tous les types de marteaux.”

– “Oui, c’est sûr.”

– “Donc, à la place, on a commencé à vendre les plans de constructions de la fabrique de marteaux, afin que nos clients puissent construire leurs propres fabriques, complètement personnalisées pour produire uniquement les types de marteaux dont ils ont besoin.”

– “Laissez-moi deviner. Vous ne les vendez plus.”

– “Non. Bien entendu. Il se trouve que les gens ne veulent pas construire toute une fabrique juste pour faire quelques marteaux. Laissez la construction des fabriques aux experts de construction de fabriques, c’est ce que je dis toujours !!”

– “Et je vous approuve sur ce point.”

– “Et oui. Donc nous avons arrêté de vendre ces plans et nous avons commencé à vendre des fabriques de fabriques de marteaux. Chacune d’elle est construite par nos experts dans le business de fabrique de fabrique de marteaux, afin que vous n’ayez pas à vous inquiéter des détails triviaux de la construction d’une fabrique. Malgré cela, vous avez tous les bénéfices d’avoir votre propre fabrique personnalisée, produisant vos propres marteaux personnalisés, collant à vos designs spécifiques en matière de marteau.”

– “Heu, ça ne me semble pas vraiment…”

– “Je sais ce que vous allez dire !! … et nous ne les vendons d’ailleurs plus. Apparemment, peu de gens achetaient ces fabriques de fabrique de marteaux, donc nous avons trouvé une solution à ce problème.”

– “Hum.”

– “Nous avons pris le temps de faire le bilan de notre infrastructure technique, et nous avons déterminé que les gens développaient une frustration à avoir à gérer et opérer une fabrique de fabrique de marteaux, tout comme la fabrique qu’elle produisait. Ce genre de contrainte additionnelle peut se révéler fastidieux quand vous vous retrouvez dans un scénario où vous utilisez également une fabrique de fabrique de mètres, une fabrique de fabrique de scies et une fabrique de fabrique de niveaux. Sans compter un conglomérat de transformation du bois. Nous avons objectivement évalué la situation, et déterminé que c’était trop complexe pour quelqu’un qui voulait juste créer une étagère pour condiments”.

– “Non, sans blague ?”

– “Du coup cette semaine, nous mettons sur le marché une fabrique de fabrique de fabrique de création d’outils en tout genre, pour qu’ainsi vos différentes fabriques de fabrique à outils puissent être créées à partir d’une seule fabrique unifiée. La fabrique de fabrique de fabrique produira uniquement la fabrique de fabrique dont vous avez réellement besoin, et ainsi ces fabriques de fabrique produiront une seule fabrique basée sur vos spécifications d’outils personnalisés. Vous aurez *exactement* le marteau dont vous avez besoin, et exactement le bon mètre pour votre tâche, juste en appuyant sur un bouton (même si vous aurez probablement quelques fichiers de configuration pour que tout fonctionne selon vos attentes).

– “Donc, vous n’avez pas de marteaux ? Pas du tout ?”

– “Non. Si vous voulez vraiment une étagère à condiments de haute qualité, de standard industriel, vous avez vraiment besoin de quelque chose de plus sophistiqué qu’un simple marteau acheté à la quincaillerie du coin.”

– “Ok… Bon. Il faut ce qu’il faut. Si c’est comme ça qu’on fait maintenant, il faut bien que je m’y mette.”

– “Excellent !!”

– “Ça vient avec une documentation, pas vrai ?”

]]>
http://sametmax.com/le-bonheur-des-frameworks/feed/ 13
Créer un site avec bottle en 5 minutes (parceque 7 c’est impossible voyons !) 17 http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/ http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/#comments Mon, 13 Aug 2012 03:55:28 +0000 http://sametmax.com/?p=1660 Aller bande de feignasses c’est Lundi on oublie la murge du week-end et on se secoue les neuronnes !

Bottle est un micro-framework python sur lequel Sam m’a obligé de bosser après Django, (il me force à évoluer c’est une horreur). Je dois dire que je le regrette pas car c’est diablement efficace, mignon et tout et tout.

En début de semaine je me suis dit qu’il fallait que j’en parle, je vais donc vous montrer comment on peut développer un “site” simple en 5 minutes structuré et sans se prendre le choux. Sam viendra compléter mes oublis.

Je ne vais pas aborder la base de données mais il y a plein de plugins bottle ici dont un ORM pour sqlite qu’on détaillera dans un article le jour où on s’en servira ;)

Avant de commencer: Pourquoi je l’aime ?

  • Simple à comprendre
  • bien structuré (des vues des templates, un routing clair)
  • gestion des urls fastoches
  • un petit serveur web intégré, on démarre son site en 10 secondes et on debug avec ipdb
  • une doc formidabuleuse avec des exemples concrets
  • il cracke les watts

En route simone !

On prend la bite rude de créer un environnement virtuel et on fait un pip install bottle. Pour ceux qui veulent tout saloper faites juste un pip install bottle, pour ceux qui savent pas ce qu’est “pip” faites un “wget http://bottlepy.org/bottle.py” dans le dossier de votre projet.

je veux que ça marche tout de suite !

Editez un fichier python start.py à la racine de votre projet et collez ça dedans:

from bottle import Bottle, run
 
app = Bottle()
 
@app.route('/')
def hello():
    return "Max est le plus beau!"
 
run(app, host='localhost', port=8080)

maintenant dans le shell tapez dans le dossier de votre projet où se trouve start.py:

python start.py 
Bottle server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
 
localhost - - [12/Aug/2012 23:12:15] "GET / HTTP/1.1" 200 21
localhost - - [12/Aug/2012 23:12:16] "GET /favicon.ico HTTP/1.1" 404 742

Ouvrez le navigateur Internet explorer bourré de toolbars à l’adresse 127.0.0.1:8080

C’est bon ça marche, c’est fini, vous êtes un pro du pot. Quand on voit ça on se dit que franchement ça sert à rien de se faire chier plus que ça… :)

Moi quand je vois ça ça me fait chialer à chaque fois tellement c’est simple, je me dis que je vais révolutionner le monde, conquérir la planète, me taper les plus belles meufs…

Avant d’aller plus loin je reprends le code et je note ce qu’il faut retenir

1. le routing

@app.route('/')

@app.route(‘/’) prend tout ce qui arrive à la racine de l’url et le traite dans la vue hello qui est une fonction de base toute simple. si j’avais voulu faire une url du genre 127.0.0.1:8080/samapoil j’aurais mis @app.route(‘/samapoil’)

2. les vues

def hello():
    return "Max est le plus beau!"

la vue est une fonction que l’ont défini et qui peut prendre n’importe quel nom, dedans on traite l’information qui arrivera de l’url routée par le décorateur “@app.route(‘/’)”. Cette vue peut recevoir des infos d’un formulaire ou des variables passées dans l’url (qu’on va voir plus bas)

Voilà votre premier site bottle marche, c’est rigolo. Maintenant on va aller un peu plus loin et utiliser les templates.

Les templates c’est quoi ?
Les templates c’est juste du code HTML avec dedans des “variables” que l’on va peupler dans notre vue. ça sert à ne pas trop mélanger code python et html et c’est plutôt une bonne idée.

Création d’un template:
éditez un fichier template.tpl et mettez dedans

<div align="center">{{ title }}</div>

Maintenant on va assembler le template et la vue comme un légo:
Ouvrez le fichier start.py et collez

from bottle import Bottle, run, view
 
app = Bottle()
 
@app.route('/')
@view('template.tpl')
def hello():
    context = {'title': "Max est le plus beau"}
    return (context)
 
run(app, host='localhost', port=8080)

Relancez le serveur (python start.py) et allez sur à l’adresse 127.0.0.1:8080

Et voilà notre template utilisé par notre vue auquel on a passé un title. Ceci ce fait grace au décorateur “@view” auquel on donne le chemin du template. Les templates offrent pas mal de possibilitées

Les bases sont posées ce n’est vraiment pas sorcier, je rajoute quelques exemples pratiques mais tout ceci figure dans la doc

Mettre un id dans l’url:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from bottle import Bottle, run, view
app = Bottle()
 
@app.route('/:mon_id')
@view('template.tpl')
def hello(mon_id):
    """
        Récupre la variable mon_id passée dans l'url sous la forme 127.0.0.1:8080/1 et la transmet au template via le context
    """
    context = {'title': "Max est le plus beau %s" % mon_id}
    return (context)
 
run(app, host='localhost', port=8080)

Récupérer une variable dans l’url:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from bottle import Bottle, run, view, request
 
app = Bottle()
 
@app.route('/jemesure')
@view('template.tpl')
def hello():
    """
        Récupère la variable taille à l'aide de l'objet request pour l'url 
        http://127.0.0.1:8080/jemesure?taille=133
    """
    context = {'title': "Je mesure %s cm" % request.params.taille}
    return (context)
 
run(app, host='localhost', port=8080, reloader=True)

Notez le “reloader=True” qui permet au serveur de redémarrer à chaque modif du code, hyper pratique.

Edit:

Servir les images, js, css (appelé contenu statique):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from bottle import Bottle, run, static_file
app = Bottle()
 
@app.route('/static/<filename:path>')
def server_static(filename):
    """
        Sert les fichiers statiques tel que .js, .css, .jpeg, etc...
    """
    return static_file(filename, root='.')
 
run(app, host='localhost', port=8080, reloader=True)

Grace à static_file vous pourrez servir vos images, faire télécharger des fichiers, etc, simplement. Dans l’exemple ci-dessus si vous allez sur l’url http://127.0.0.1:8080/static/template.tpl vous allez télécharger le template template.tpl, si c’est une image, votre navigateur affichera une image, etc…

Je vous conseille d’aller voir la doc histoire de vous mettre l’eau à la bouche. JE déteste les docs en général mais là je la trouve presque parfaite.

Sam vous fera un article bientôt sur comment mettre tout ça en prod car le petit serveur web compris dans bottle ne peut bien sur pas assurer une charge en prod.
Mais comme dit ma grand-mère ça se goupille comme un doigt au cul.

Bottle est vraiment pour moi l’outil parfait pour concrétiser rapidement une idée, un site qui ne demande pas une grosse structure, bref un projet qui doit se torcher rapidement ;)

Et pour illustrer ce que j’ai pu faire en quelques jours de taf avec bottle et un peu de Jquery je vous mettrai en ligne dans la semaine un petit site fort symphatique je pense…

]]>
http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/feed/ 17
Schéma de fonctionnement général de Django 12 http://sametmax.com/schema-de-fonctionnement-general-de-django/ http://sametmax.com/schema-de-fonctionnement-general-de-django/#comments Thu, 21 Jun 2012 21:04:42 +0000 http://sametmax.com/?p=964 Les frameworks Web rendent ceux qui les maitrisent très productifs, mais pour débuter, quelle galère ! On a envie de retourner à ses vieux scripts tout pourris mais bien plus facile à comprendre. Et c’est normal, on est pas la pour se toucher devant la qualité du code, mais pour obtenir un truc qu marche (dédicace à Max).

Voici une explication du fonctionnement global de Django. Comme ça la prochaine fois que vous lisez un tuto Django et qu’on demande d’insérer un blougou à sens giratoire inversé dans le convecteur temporel, vous ne saurez toujours pas de quoi on parle, mais vous saurez où ça se trouve.

Le protocole HTTP

Pour comprendre ce que fait Django, il faut piger le fonctionnement du Web. Si vous savez ce qu’est une requête POST et que la notion de headers et de cookies ne vous parait pas complètement glucose, vous pouvez sauter cette partie. Les autres, n’ayez pas honte, il y a des centaines de dev Web là dehors ne savent pas comment ça marche.

En résumé, se balader sur le Web, c’est comme aller au resto. On est un client, on demande quelque chose au serveur, le serveur va voir en cuisine, et revient avec la bouffe, ou une explication sur l’absence de la bouffe (mais jamais pourquoi la bouffe est dégueulasse, allez comprendre):

Schéma du protocole HTTP, en gros

Le protocole HTTP, en (très) gros

Ce cycle requête/réponse se déroule des centaines de fois quand on parcours un site Web. Chaque lien cliqué déclenche une requête GET, et la page suivante ne s’affiche que parcequ’on a reçu la réponse contenant le HTML de celle-ci. Les formulaires, les requêtes AJAX, la mise à jour de vos Tweets sur votre téléphone, tout ça fonctionne sur le même principe.

Django dans tout ce merdier

Django est un framework Web, le serveur lui fait passer chaque requête GET, POST (ou autres) envoyée par les clients. Django, lui, génère un contenu pour chacune d’elle (souvent du HTML), et le refile au serveur qui renvoit la réponse au client. En détail, ça donne ça:

Schéma du cycle de vie d'une requête traitée par Django

Le cycle de vie d'une requête traitée par Django

Django ce n’est que ça. Il n’y a rien de mystérieux: la requête arrive, on prend un template, on dit à Django de mettre des données récupérées depuis la base de données dans le template, on génére du HTML, on retourne la réponse. Le reste (le gros reste), ce sont juste des outils pour automatiser toutes les variantes de ce cycle: formulaire, flux RSS, gestion de droits, etc. Mais tout tourne TOUJOURS autour de la logique requête/réponse car le but est de faire du Web, et que le Web marche comme cela.

Vocabulaire

La difficulté de Django vient aussi du vocabulaire car on utilise des mots compliqués pour désigner des trucs simples.

Urlresolvers: la partie de Django qui reçoit la requête, la compare à une route dans urls.py, et appelle la bonne vue de views.py
Template processor: la partie de Django qui permet de récupérer un template par son nom, de lui passer des données, et de récupérer du HTML sans se fouler. On l’utilise rarement directement, généralement on passe plutôt par une fonction raccourcie comme render().
Template Context: un simple dictionnaire dont les clés sont les noms des variables qu’on veut rendre disponibles dans un template, et les valeurs sont les valeurs de ces variables. On créé ce dictionnaire dans un vue, et on le passe au template processor pour obtenir du HTML à partir d’un template.
Tags et filters: des fonctions Python castrées pour pouvoir être utilisées dans un template (puisque le template est là pour limiter l’usage de fonctions dans le HTML)

Vous avez dû noter des asterisques sur le schéma de fonctionnement de Django. Ce sont les endroits où agissent deux parties de Django particulièrement mal comprises:

* Middleware: un nom pompeux pour dire “Une classe Python normale avec une methode appelée à chaque requête, et une méthode appelée à chaque réponse.” En gros, c’est votre moyen d’appliquer un traitement à toutes les requêtes ou les réponses. Par exemple si vous voulez rediriger tous les mobiles vers une version mobile d’un site, vous faite une classe dont une méthode vérifie le contenu de chaque requête, regarde si le Header “User-Agent” est un mobile, et court-circuite la réponse pour rediriger immédiatement. Il suffit de déclarer cette classe comme middleware dans le fichier settings.py et ça marche tout seul.
** Context processor: un nom pompeux pour dire “Une fonction Python normale qui accepte un Template Context (un simple dictionaire) en entrée, et qui le retourne modifié.” On l’utilise quand on veut qu’une valeur soit disponible dans tous les templates, par exemple en rajoutant la date du jour dans le Template Context.

C’est tout. Vraiment, c’est tout. Le reste c’est du bonus. Django c’est juste ça.

]]>
http://sametmax.com/schema-de-fonctionnement-general-de-django/feed/ 12