PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Pourquoi les nouveaux programmeurs ne lisent plus le code source des autres 80

dimanche 21 juin 2015 à 11:59

Dans un ancien post sur son blog, Raymond Hettinger s’attristait de voir les devs lire de moins en moins le code source. Bien qu’il datait de plus de 4 ans, je n’ai pas pu m’empêcher de répondre. Puis je me suis dis que la traduction aurait tout à fait sa place ici.

La cause de ce phénomène est très culturel. J’enseigne à mes étudiants que si ils veulent en savoir plus sur le fonctionnement d’un bout de code d’un module, ils peuvent juste faire :

import module
print(module.__file__[:-1])

Puis ouvrir le fichier dont ils obtiennent ainsi le chemin dans leur éditeur préféré. Cela marche en tout cas pour tous les modules en pur Python.

En fait, si vous utilisez ipython, vous pouvez même faire :

!votreediteur module.__file__[:-1]

Et ça l’ouvrira directement. Par exemple :

!subl module.__file__[:-1]

Malgré cette information, ils ne le font jamais.

En partie parce qu’ils ont peur.

En partie parce que plus personne n’enseigne cet état d’esprit à l’université ou dans les tutos.

Mais essentiellement parce que toute autre méthode est plus productive, donc ils sont formés à utiliser à peu près tout sauf regarder le code source.

Chercher sur Google, demander sur un site d’aide, sur IRC, une mailling list, à un collègue, brute forcer tous les snippets qui traînent en les copiant/collant à la chaîne, et même, Dieu nous garde, lire la doc. Tout cela est plus facile et rapide que de lire le code source, parce lire les sources part du principe qu’on comprend comment tout marche.

Il y a aussi le fait que lire le code source il y a 30 ans était compétitif avec les autres options de consultation, tandis qu’aujourd’hui de nombreux devs ont 4 ordis chez eux avec un accès haut débit à la connaissance du monde entier.

Et bien sûr, ils se sont habitués à la vitesse. Et plus que ça, leurs enseignants/boss s’y sont habitués, et leur comportement communique implicitement cette attente, ce qui amène à ne pas lire les sources.

Cela m’a pris 5 ans de programmation pro avant de commencer à regarder les sources par moi-même de manière régulière. J’y ai été forcé, ayant beaucoup travaillé en Afrique et en Asie où avoir l’info hors ligne est un avantage.

Malgré cela, je ne le fais que pour le code Python, car mes talents en C sont faibles et je n’ai jamais pris le temps de télécharger les fichiers C. Je sais pertinemment que la programmation C est un atout important à avoir. Je souhaite l’apprendre. Et Rust, et Erlang, et Haskell, et l’espagnol et m’améliorer dans le gestion des CSS, l’administration système, la sécurité des systèmes, et essayer Riak, et OpenStack… Bien entendu, ça c’est juste la partie technique, j’ai une vie très pleine à côté.

Car voilà la seconde partie de la vérité : l’époque où on pouvait maitriser tout le champ de connaissance en informatique est révolue.

Je passe une HEURE, tous les jours, juste pour me mettre à jour dans mon ridicule petit champ d’expertise, et je n’ai même pas le temps de tout lire, encore moins de pratiquer. C’est 300 heures par an juste pour garder la tête hors de l’eau.

Maintenant, imaginez les débutants. Ils débarquent dans ce monde avec tellement de langages, de libs, de frameworks, d’outils, de technos ! Tellement de couches et de niveaux d’indirection ! Ils vont essayer d’obtenir la réponse aussi facilement qu’ils le peuvent, parce que la somme de connaissances accumulées qui permettent de lire les sources (ce n’est pas un acte simple, c’est une illusion qui bercent ceux qui sont devenus assez bons pour le faire sans effort), cette montagne, nous avons eu beaucoup plus de temps pour l’escalader qu’ils en ont. Et malgré cela, ils ont plus de choses que nous à apprendre.

Or le temps ne s’arrête pas pour autant, et l’expérience du marché se transforme. Les clients s’attendent aujourd’hui à des expériences logicielles bien plus complexes: designs léchés, animations, vitesse, connectivité, synchronisation, notification en temps réel, interconnexion de services, Web APIS, recherche intelligente, présentation contextuelle et personnalisée de l’information, traitement de médias riche… Et ça c’est juste pour des produits app/Web, car chaque marché a vu les attentes grandir.

Donc on attend d’eux qu’ils livrent tout ça, car les concurrents le font. Mais sans les y former, et si possible sans les payer trop cher. Et ASAP, évidement.

Les gens que je forme vont chercher un moyen d’obtenir le résultat dont ils ont besoin aussi vite que possible, avec aussi peu d’effort que possible.

C’est triste, mais je comprends parfaitement.

Nouveau fichier de start up Python 9

samedi 20 juin 2015 à 20:20

Régulièrement je passe un coup de dépoussiérage sur mes outils, et aujourd’hui c’est le tour du script de start up.

Pour ceux qui ne se souviennent pas, on peut utiliser la variable d’environnement PYTHONSTARTUP pour choisir un script de démarrage pour le shell.

Ca attend un chemin absolu vers un fichier Python, et donc sous Mac et Linux, on met dans son .bashrc ou équivalent :

export PYTHONSTARTUP=/chemin/vers/son/script.py

Sous Windows, on ouvre une console et on fait :

SETX PYTHONSTARTUP c:\chemin\vers\son\script.py

Et dedans on peut mettre tout le code Python qu’on veut, ça sera lancé automatiquement quand on démarre le shell, mais PAS quand on lance un script Python.

Le script est exécuté dans l’espace de nom du shell, donc tous les imports du script sont mis à la disposition du shell. Du coup, pour moi il contient :

# -*- coding: utf-8 -*-
 
# faut que ça marche pareil en P2 et P3
from __future__ import unicode_literals, print_function, absolute_import
 
# Les imports des modules de la libs standars que j'utilise le plus
# car à force çe me gave de les réimporter moi-même à chaque session
import sys
import os
import re
import json
import csv
import random
import hashlib
import tempfile
import random
import shelve
import atexit
import subprocess
from glob import glob
from uuid import uuid4
from pprint import pprint
 
# on shadow le open() builtin histoire d'avoir toujours le
# paramètre encoding
from codecs import open
 
from itertools import *
from collections import *
from datetime import datetime, timedelta
 
# imports d'outils tierces parties que j'utilise souvent mais qui pourraient ne
# pas être installés
try:
    import arrow
except ImportError:
    pass
 
try:
    import requests
except ImportError:
    pass
 
try:
    from path import path
except ImportError:
    pass
 
try:
    from minibelt import *
except ImportError:
    pass
 
# activation d'autocompletion si ce n'est pas déjà le cas, notamment sous
# des vieux shell Python ordinnaire
try:
    import rlcompleter
    import readline
    readline.parse_and_bind("tab: complete")
except ImportError:
    pass
 
# si on est dans un virtual env
env = os.environ.get('VIRTUAL_ENV')
if env:
 
    # afficher le nom de l'env dans le prompt (marche pas dans ipython qui
    # a sa propre config pour ça)
    env_name = os.path.basename(env)
    sys.ps1 = '(%s) %s ' % (env_name, getattr(sys, 'ps1', '>>>'))
 
    # affichage une fois des modules installés avec pip pour qu'on sache
    # ce qu'on a a dispo dans cet env
    print("\nVirtualenv '{}' contains:\n".format(env_name))
    cmd = subprocess.check_output([env + "/bin/pip", "freeze"],
                                  stderr=subprocess.STDOUT)
    try:
        cmd = cmd.decode('utf8')
    except:
        pass
 
    cmd = cmd.strip().split("\n")
    p = re.compile(r'(^.*\:\s)|((#|@).*$)|(==.*$)')
    print("'" + "', '".join(sorted(set(os.path.basename(p.sub('', f)) for f in cmd))) + "'\n")
 
 
# alias pour printer rapidement
p = print
pp = pprint
 
# avoir toujours un dossier temporaire près à l'usage
TEMP_DIR = os.path.join(tempfile.gettempdir(), 'pythontemp')
try:
    os.makedirs(TEMP_DIR)
    TEMP_DIR = path(TEMP_DIR) # si possible un objet path
except Exception as e:
    pass
 
# avoir un dico persistant pour garder des objets entre deux sessions. Pratique quand
# on a un gros array numpy qu'on n'a pas envie de se faire chier à se recréer
class Store(object):
    def __init__(self, filename):
        object.__setattr__(self, 'DICT', shelve.DbfilenameShelf(filename))
        # cleaning the dict on the way out
        atexit.register(self._clean)
 
    def __getattribute__(self, name):
        if name not in ("DICT", '_clean'):
            try:
                return self.DICT[name]
            except:
                return None
        return object.__getattribute__(self, name)
 
    def __setattr__(self, name, value):
        if name in ("DICT", '_clean'):
            raise ValueError("'%s' is a reserved name for this store" % name)
        self.DICT[name] = value
 
    def _clean(self):
        self.DICT.sync()
        self.DICT.close()
 
# Ainsi on peut faire store.foo = 'bar' et récupérer store.foo à la session
# suivante. Moi je store tout dans un truc temporaire mais si vous voulez
# garder la persistance entre deux reboots, il suffit de choisir un autre
# dossier. 
python_version = "py%s" % sys.version_info.major
store = Store(os.path.join(TEMP_DIR, 'store.%s.db') % python_version)

Il est un peu relou puisqu’il faut qu’il marche pour P2 et P3…

Je me demande si je devrais pas faire un repo pour ce genre de truc.

IndexErrorCoders, le compte github de la communauté d’IndexError 24

mardi 16 juin 2015 à 15:59

C’est pas moi, j’ai rien fais !

J’ai reçu une notif m’invitant à participer à ce groupe de travail, et en regardant de plus près, j’ai vu qu’il s’appelait IndexErrorCoders.

Après investigation, il est né d’une question sur IndexError qui, commentaire après commentaire, à abouti à la création d’un repo git dédié aux design patterns Python.

C’est toujours sympas de voir les trucs qui se forment autour de notre petite communauté, on a l’impression de vivre dans une coloc avec tout le monde :)

Bonne chance au projet.

La mort du tuto angular 27

dimanche 14 juin 2015 à 20:25

J’avais demandé si il y avait encore des gens intéressés par le tuto angularjs que j’avais commencé. En effet les ressources sur Angular sont généralement de mauvaise qualité, et la réponse avait été un gros OUI.

Je m’étais donc mis en tête de continuer. Malgré la mort annoncée du framework. Malgré une V2 qui va tout casser.

Voyez-vous, j’aime Angular. Bien que je pense que pour des grosses apps une approche comme ReactJS + BackboneJS est plus saine, pour une petit app rapide ou du prototypage c’est très productif et pratique.

En plus, je n’aime vraiment pas manquer à mes engagements, et en presque 3 ans de ce blog, je les ai tenu. J’ai toujours publié les articles promis. Toujours répondu aux mails. Parfois avec des mois de retard, certes, mais je n’ai signé aucun contrat moral sur les deadlines :)

Je vais néanmoins faire une exception ici et envoyer le tuto Angular au cimetière. Toute mes excuses à ceux qui l’attendaient.

Bien sûr il y a le fait que j’ai beaucoup de travail. Cependant si c’était la cause principale je n’écrirais plus ici car ça me demande des heures et des heures chaque semaine.

C’est surtout qu’il se trouve que j’avorte régulièrement des tentatives de retravailler dessus. C’est un signe de manque de motivation certain, et je viens d’en comprendre aujourd’hui la raison : c’est du Javascript.

Jusqu’ici le blog s’était autorisé régulièrement des sorties de la ligne éditoriale, mais un tel travail, un guide complet sur Angular, enterine le JS comme un sujet majeur du site.

Or ce n’est pas le cas.

Je n’aime pas Javascript.

Du coup non seulement me motiver à faire le dossier me demande une énorme énergie (qui pour le moment se transforme en procrastination coupable), mais en prime je me dis que c’est dépenser des ressources pour faire le taff d’une communauté qu’au final je ne supporte que par obligation professionnelle.

Le résultat est donc que bien que je vais continuer à parler de JS et à coder en JS (programmation Web oblige), je ne vais pas lui accorder autant de place sur S&M ou dans mes heures de loisir.

Je remercie ceux qui prennent le temps de le faire, après tout je profite de leur travail. De mon côté, je vais me concentrer sur les domaines qui me sont plus chers, et parler d’autre chose uniquement de manière ponctuelle. L’investissement me parait plus judicieux.

Le problème avec les plans de cours 5

samedi 13 juin 2015 à 19:54

Quand je suis sollicité pour une formation, l’organisme demandeur requiert souvent un plan de cours.

Je le fournis toujours, et la première chose que je fais en commençant la formation, c’est de le mettre à la poubelle.

Pourquoi ?

D’une part, j’essaye toujours de contacter les participants avant, afin d’analyser leurs besoins réels. Pas ceux imaginés par l’organisme de formation, les RH, le training manager, le chef d’équipe ou leur fanstasme sur ce qu’ils doivent faire.

Non, je demande ce qu’ils font au quotidien, leurs missions, leurs postes, leurs tâches, leurs envies, leurs styles, leurs objectifs et projets. J’en déduis des notions clés, et je leur propose. Ils me corrigent, et on arrive à quelque chose d’utile.

Mais même ainsi, si je me limitais à organiser ces notions en un document avec des grands titres qui regroupent tout ça par thème ou pas unité de temps, puis ordonnés sous forme de liste, je ne remplirai pas ce contrat le jour J.

En effet, un plan de cours est linéaire, tandis que l’enseignement ne l’est pas.

Prenez par exemple les chaînes de caractères. On pourrait se dire que c’est la base, on en parle au début et c’est bon.

Pas du tout.

Voici toutes les notions liées aux chaînes de caractères en Python qu’on peut aborder dans une formation pour débutants :

Et là je ne parle même pas de la notion du sens du texte. Je ne parle pas des fichiers. Je ne parle pas d’extraction complexe avec des regex. Je ne parle pas de l’utilisation du texte dans un protocole de communication ou un outil de sérialisation. Je ne parle pas de format de contenu comme sphinx ou les doctests. Je parle bien juste de la structure de données, le truc le plus basique du langage, une des notions les plus primitives qui sert de socle à toutes les autres.

Bien entendu tous ces aspects ne sont pas utiles tout de suite, et on les introduit au fur et à mesure de la formation. Contextuellement.

Toutes les notions sont comme ça. Les centaines nécessaires à l’apprentissage du langage ont de multiples facettes, qui ne sont pas présentables en bloc.

On ne les enseigne pas pour en faire le tour, on en prend un petit bout, on le mélange avec le reste, comme on prendrait des fils qu’on croiserait alors pour tisser un vêtement.

Un plan qui dirait: on voit les strings ici, et c’est finit, ne ferait que mentir. Mais un plan qui dirait la vérité ferait 10 pages de listing alambiqué rempli de concepts qui s’entrecroisent sans même donner leurs interactions pourtant indispensables. Dans tous les cas, rien de pertinent.

Pourquoi je l’écris alors ?

Essentiellement pour deux raisons :

D’abord une raison administrative. Beaucoup de dossiers requièrent un plan, afin de démontrer que le prestataire sait de quoi il parle. Mais surtout, les commerciaux ont besoin d’un plan pour avoir quelque chose de concret sur lequel s’appuyer pour faire leur vente.

La seconde raison est pour que les gens qui vont à la formation, sachent à quelle sauce qu’ils vont être mangés. C’est vrai, le plan ne reflète en aucun cas la réalité de la formation, mais il va donner une idée de ce qu’on va aborder. On peut ainsi faire ses choix, demander des amendements, s’y préparer, etc.

Aussi, quand vous faites un cours, ne rejetez pas l’importance de faire un plan. Mais libérez-vous en dès que vous faites le premier pas dans la salle de cours. Il est des contrats qu’il faut savoir briser.