PROJET AUTOBLOG


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

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

⇐ retour index

Le don du mois : Tor 11

jeudi 7 janvier 2016 à 10:57

Comme chaque mois, je fais un petit don à une entité et je fais sa pub. Premier don de 2016 : Tor, le logiciel le logiciel d’anonymisation de connexion Internet.

Je l’utilise pourtant peu. De temps en temps, je reinstalle tout le bordel, et je regarde où ça en est. Parfois, je fais un bot qui a besoin de plus d’IP et je le plug temporairement sur Tor. Mais ce n’est pas un usage régulier.

Pourtant, philosophiquement, je trouve que sa mission est de la plus haute importance : nous accumulons de l’expérience sur la mise en place d’un Internet plus démocratique, plus ouvert, moins centralisé, plus humain.

Or Internet est dévenu le cerveau connectant l’humanité entière, et il faudra bien cela, et beaucoup d’autres choses, pour s’assurer que les pensées de tous s’y reflètent, et pas juste celles d’une minorité.

Pour cela, je soutiens le développement de Tor. Je pense que ses jours sont pourtant comptés, mais sa simple existence a été primordiale à la santé d’Internet.

50 euros, en bitcoin, pour ce don.

Pourquoi utiliser un mécanisme d’exceptions ? 18

mercredi 6 janvier 2016 à 01:17

L’article ne vient pas de nulle part. En fait j’ai dû dans la même journée répondre sur le subreddit Python à cette question et à un lecteur par email, alors je me suis dit qu’il serait bon de faire le point ici.

Avant de lire l’article, assurez-vous de bien avoir compris la gestion des erreurs en Python.

La réponse simple, courte, et définitive

“Pourquoi utiliser un mécanisme d’exceptions ?”

Parce que c’est la manière de faire que de la communauté du langage que vous utilisez.

Si vous êtes dans un langage qui utilise des codes de retour comme C, alors gérez les erreurs avec des codes de retour. Si vous avez du pattern matching comme en Rust, utilisez le pattern matching. Si vous avez des exceptions comme en Java, utilisez les exceptions. Si vous avez des guards comme en swift, vous utilisez des guards.

Je crois que vous avez pigé.

Ceci est la règle, qui est complètement indépendante de la qualité du système de gestion des erreurs : codez dans le style approprié pour le langage et n’essayez pas de bricoler votre solution perso dans votre coin. Si ça vous fait chier, changez de langage. Mais ne faites pas du pseudo-Go en Erlang, ça n’a pas de sens, et ça va saoûler tous vos collègues, en plus de diminuer l’intégration avec l’écosystème de la techno.

En Python, les erreurs (et même plus) sont gérées via un mécanisme à base d’exceptions, et c’est donc ce qu’il faut utiliser.

Maintenant, un mécanisme de gestion d’erreurs est vraiment une question de goût. Il n’y en a pas de parfait, mais il peut être intéressant de connaitre les points forts de celui qu’utilise Python.

Quels sont donc les points forts d’un mécanisme à base d’exceptions ?

Cela évite les races conditions

En informatique, dès qu’un système peut faire plusieurs choses à la fois, plusieurs choses peuvent arriver simultanément et créer ce qu’on appelle une race condition.

Par exemple, si je fais ceci:

# on vérifie que le fichier existe avant de l'ouvrir
if os.path.isfile('monfichier'): 
    with open('monfichier') as f:
        print(f.read())
else:
    print('pouet')

Entre la première ligne et la seconde ligne s’écoule un temps très court pendant lequel un autre processus peut supprimer le fichier et faire planter mon programme.

En utilisant la philosophie “il est plus facile de demander pardon que la permission”, on évite ce problème:

try:
    # on s'en bat les couilles, on essaye
    # de l'ouvrir à sec
    with open('monfichier') as f:
        print(f.read())
except OSError:
    print('pouet')

Dans ce cas on tente d’ouvrir le fichier de toute façon, et si l’ouverture déclenche une erreur, alors on la gère. Pas de race condition.

Finally et with pour les opérations de nettoyage

En ouvrant mon fichier, je dois m’assurer de le fermer après. Mais je peux avoir une erreur à l’ouverture du fichier, ou pendant sa lecture, qui fasse planter mon programme et que je n’avais pas prévue.

Comme les exceptions remontent la file d’appel, on peut les attraper à plusieurs niveaux. Grâce à finally (et with qui enrobe finally), on peut donc très élégamment s’assurer que les opérations de nettoyage sont lancées automatiquement, même si tout pête:

# ouvrir un fichier avec with garantit sa fermeture
with open('monfichier') as f:
    print(f.read())

Les exceptions sont très explicites

Des mécanismes comme le pattern matching ou le retour de codes sont génériques, et peuvent être utilisés pour à peu près tout.

Les exceptions, à l’image des guards, ont un champ d’usage plus restreint, et quand on en voit, on sait donc généralement à quoi s’en tenir. Cela facilite la lecture en diagonale du code.

Les exceptions décrivent une hiérarchie d’erreurs

Ceci permet non seulement de choisir de gérer plusieurs erreurs d’un coup, ou alors séparément, mais également de documenter par le type quel est le problème. Une fois qu’on connait les exceptions les plus courantes en Python (ValueError, OSError, KeyError, TypeError, etc.), on identifie vite l’idée générale d’un message d’erreur ou d’un code attrapant une erreur.

Comme on peut créer ses propres types d’exceptions, on peut permettre le ciblage des erreurs d’une lib en particulier, ou d’un sous ensemble d’une lib ou d’une opération. Et c’est aussi une forme de documentation par le code.

Tout cela autorise une fine granularité sur ce qu’on veut gérer ou pas : tout d’un coup, au cas par cas, seulement sur une partie du code, etc.

Les exceptions bubblent

Sous ce terme barbare se cache le fait que les exceptions se déclenchent localement dans un bloc de code, et l’interrompent, mais ne font pas planter le programme tout de suite. À la place, l’exception monte d’un niveau dans la file d’appels, et casse tout, puis remonte d’un cran, et casse tout, et ainsi de suite, jusqu’en haut.

Ce mécanisme permet de choisir exactement où on veut arrêter l’exception, et ce que l’on souhaite qu’elle puisse interrompre. Cela laisse le choix de gérer des erreurs de manière macroscopique ou microscopique.

Par exemple, si j’utilise un try en dehors d’une boucle :

print('start')
try:
    for x in range(0, 10):
        print(1 / (x - 2))
except ZeroDivisionError:
    pass
 
print('fin')
## Affiche :
## start
## -0.5
## -1.0
## fin

Et un dans une boucle :

print('start')
for x in range(0, 10):
    try:
        print(1 / x)
    except ZeroDivisionError:
        print('ERROR !')
    else:
        print("Pas d'erreur :)")
    finally:
        print('TOUJOURS')
print('fin')
## Affiche:
## start
## ERROR !
## TOUJOURS
## 1.0
## Pas d'erreur :)
## TOUJOURS
## 0.5
## Pas d'erreur :)
## TOUJOURS
## 0.3333333333333333
## Pas d'erreur :)
## TOUJOURS
## 0.25
## Pas d'erreur :)
## TOUJOURS
## 0.2
## Pas d'erreur :)
## TOUJOURS
## 0.16666666666666666
## Pas d'erreur :)
## TOUJOURS
## 0.14285714285714285
## Pas d'erreur :)
## TOUJOURS
## 0.125
## Pas d'erreur :)
## TOUJOURS
## 0.1111111111111111
## Pas d'erreur :)
## TOUJOURS
## fin

J’obtiens un résultat radicalement différent. On peut choisir facilement l’étendue de la propagation de l’erreur.

Les exceptions ont des données attachées

Les exceptions sont des objets riches, qui viennent avec un message d’erreur, un contexte qui permet de générer une stack trace, et parfois des attributs en plus comme le code d’erreur fourni par l’OS.

C’est un point d’entrée capable de concentrer en un seul endroit tout ce dont on a besoin pour le debug.

Pas cher mon fils

En Python, les exceptions sont particulièrement peu couteuses à utiliser. En fait, Python les utilise pour le contrôle de flux (StopIteration, GeneratorExit, etc) donc elles sont au coeur du fonctionnement du langage, et pas juste pour pour les erreurs.

Faire un try/except n’a pas le coût qu’on a en Java ni en terme de performance du code, ni en terme de verbosité car il n’y a pas de throw à déclarer.

Le truc le plus ennuyeux, c’est bien entendu de trouver le nom de l’exception qu’on veut gérer et comment l’importer. Afin d’éviter cette chose affreuse:

    try:
        meh()
    except: # YOLO
        print("Il s'est passé un truc, mais je sais pas quoi")

Il y a à peine quelques heures j’étais avec un client qui avait des utilisateurs se plaignant que le système ne marchait pas sans vraiment pouvoir diagnostiquer pourquoi.

Vous voyez, pas besoin d’inventer, j’ai les exemples qui me tombent tout cru dans le bec.

Voici ce qu’il avait, en prod :

# je vous pseudo code, mais c'est l'idée
def get_dbs():
    try:
        # connection, listing, filtrage, casting
        # nahhh, que pourrait-il arriver de grave ?
        con = Connect()
        dbs = con.get_databases()
        dbs = fitler_system_db(dbs)
        return tuple(dbs)
    except: # double combo: catch all ET silence
        return ()

Oui, j’ai bien dit en prod. La base de données gère des listings de médecins. Ouch.

Le code utilisant cette fonction faisait (avant que j’arrive avec mon fouet de zorro et corrige tout ce bordel):

dbs = get_dbs()
if not dbs:
    display_error("Mongo ne tourne pas, ou la connection a échoué, ou aucune table n'est créé")

Vous imaginez comme l’utilisateur final pouvait facilement décrire son problème… Ouai alors soit t’as pas un truc, soit le truc marche pas, soit tu te sers pas du truc. Ouai ça couvre à peut prêt l’ensemble des erreurs possibles sur tous systèmes, comme ça on peut pas avoir fondamentalement tort.

EDIT:

Histoire de mettre fin au débat sur le code final qui va immanquablement envahir les coms:

Bref, faut tout réécrire. Ça tombe bien, il me paie pour ça.

Notez que face à ce genre de code, le comportement à adopter n’est pas de mettre la misère à son client, mais simplement de lister les améliorations possibles, les justifier et estimer le coût et les bénéfices des changements. On est pas la pour fanfaronner, juste pour s’assurer qu’il puisse faire son taff.

Là je me permet de faire le clown parce que ça rend l’article plus léger, et parce qu’il est américain, et ne sera donc pas impacté par l’article. De l’intérêt également d’être un blogger anonyme et francophone…

Retour sur la pénurie de devs 132

mardi 29 décembre 2015 à 13:24

Rien qu’autour de moi, on cherche pas loin de 50 devs joomla

Un de mes amis m’a rapporté cette discussion qu’il a eue avec un de ses contacts sur Nantes. Nantes n’est pas une grande ville. Et joomla est un CMS parmi d’autres. Par ailleurs, les CMS ce sont qu’une techno Web parmi d’autre. Et la prog Web n’est qu’une sorte de prog parmi d’autres.

Or je vous rappelle ce qu’on m’avait déjà sorti:

Quand on trouve un profil qui maitrise toutes les technos de notre stack, on lui sort le tapis rouge. C’est juste improbable.

Un collègue à moi, qui me disait il y a 2 ans autour d’un verre que son process de recrutement le minait.

Si tu viens ici je te trouve un poste à 220k.

Un client américain de longue date qui me recrute en remote parce que « c’est moins cher » et qui me confiait les tarifs pour mon profil étaient aberrant chez lui.

Le fait est qu’on a déjà du mal à trouver de la main-d’œuvre bien qualifiée maintenant.

Il y a plusieurs raisons à cela.

D’abord, il y a un nombre limité de devs, et une explosion du nombre de technos. Ces technos se sont, dans la dernière décennie, organisées en stacks complexes. Elles sont accumulées des process et des couches d’abstraction, qui évoluent rapidement pour répondre à la mutation des usages : mobile, streaming, temps réel, offline-mode, synchronisation….

La virtualisation, le cloud, les pré-processeurs, la variété des plateformes, le big data, etc. C’est à n’en plus finir.

Une personne ne peut pas tout savoir, et il peut être productif uniquement dans un nombre limité de domaines, nombre dont la taille — en proportion au reste du monde — se réduit année après année.

Les attentes des gens ayant évolué, faire un service web compétitif aujourd’hui demande des compétences côté client et serveur, du design et la compréhension du mobile, ne serait-ce que pour un proto tout pourri. Et ça c’est que pour le Web. N’oubliez pas l’embarqué, le sysadmin, l’analyse de données, l’exploration scientifique, le jeu vidéo, les systèmes d’information internes, les systèmes métier et tout le bordel.

Bref, il faut du monde. Du monde compétent. Ce monde est limité, et la demande augmente de par la complexification de nos outils et contraintes, comme on vient de le voir. Mais aussi par la demande technologique qui grimpe.

Car aujourd’hui nous avons des ordinateurs partout. Un dans la poche, un dans la voiture, un dans la télé et certains essayent d’en foutre dans les chaussures et le frigo. La fiche de paie, l’ordonnance du médecin, la facture de carrefour et l’avis d’imposition sont tous traités par informatique.

Ceci ne va pas ralentir. Même si on ne se rajoutait pas de nouveaux usages, et on va le faire, on a 3 milliards d’asiastiques qui sont en plein boom technologique.

Et là vous allez me dire que c’est justement l’occasion de faire du offshore pour répondre à la demande.

Mais ça ne marche pas.

J’ai suivi l’expérimentation de la sous-traitance à l’étranger des années post-bulle. A l’époque, j’ai entendu un décideur dire :

on peut très bien prendre un Indien pour pisser du code

.

J’ai aussi observé tous ces projets se planter. Une fois, j’ai vu un simple proto Web couter 140 000 euros pour au final n’avoir AUCUNE fonctionnalité. Véridique. 140 boulasses.

Ce n’est pas qu’on ne trouve pas les compétences adéquates hors de nos contrées. Au contraire. Mais il y a des tas de facteurs propres à notre industrie qui rendent l’exercice de la délégation délicate, et ça ferait un excellent article, mais je ne vais pas les exposer ici.

L’important c’est de noter qu’on en revient. Les devs indiens vont participer à l’essor de l’informatique de l’Inde. Les devs chinois à celui de la Chine. Et ils auront les mêmes problématiques que nous à différentes échelles et sous d’autres visages. Mais le croisement des effluves sera limité.

En revanche la globalisation va faire que leur expansion va, par effet de bord, augmenter notre activité informatique en plus de nos propres causes de croissance. On va avoir besoin de plus de devs.

Toujours plus, encore plus.

Des devs de plus en plus spécialisés pour des archis de plus en plus complexes.

Je ris quand les gens disent que les nouveaux venus ne sont pas « des vrais programmeurs ».

Moi je devais faire attention au nombre de cycle CPU

aujourd’hui les gens rachètent des serveurs plutôt que d’économiser de la mémoire

etc.

Ouai, ouai, pépé, tu faisais de l’assembleur, c’est viril.

Mais le gamin de 20 ans qui arrive sur le marché, on lui colle entre les pates une app react native en JSX qui une fois transpilée par babel + gulp va se faire valider dans un market pour s’installer dans une sandbox sur des terminaux hétérogènes où elle va taper à travers un réseau wifi/4G intermittent dans une API REST sur des serveurs distants organisés en microservices Django + dockers déployés sur du cloud AWS.

Le seul point commun avec les deux époques, c’est qu’il n’y a toujours pas de doc.

Donc non, l’informatique n’est pas plus facile aujourd’hui. Il y a plus à savoir. Ça change plus vite. Chacun est plus cloisonné dans sa bulle de connaissance spécialisée. Et ça s’accélère.

Les challenges sont là, juste différents, mais la demande est immensément plus forte.

Et puis vous imaginez la gueule de l’offre d’emploi pour recruter ce profil ? Doit parler anglais, 7 ans d’expérience en mécanique quantique, taper en Bépo est un plus. On paie le SMIC mais on offre le café illimité comme chez Google.

A cela se rajoute le problème que les formations ne suivent pas.

Elles ne produisent pas assez d’informaticiens.

Elles produisent des profils sur des technos qui ne sont pas à jour, qui ne correspondent pas à la demande du marché.

Et surtout, elles produisent des nazes.

Pardonnez-moi, jeunes gens, ce n’est pas personnel.

Mais 90% des gens qui sortent de l’école, je ne souhaite jamais bosser avec. Jamais.

Attention, je ne dis pas qu’ils n’ont pas experience. Ca c’est normal. Je dis qu’ils ne sont pas capable de résoudre un fizzbuzz après tout ce temps d’étude.

Ils sont mauvais, au point de ne pas savoir coder un script simple. Certains ne savent pas exprimer une idée clairement, et encore moins définir un problème. Même pas poser les bonnes questions.

Alors oui, ça peut s’améliorer une fois en entreprise, mais qui a le temps ? Qui a l’envie ? Qui a l’argent ? Investir pour former à sa stack ok, mais pas pour apprendre à faire faire un hello world.

Vous vous imaginez en train d’embaucher un cuisinier qui ne sait pas faire cuir un œuf ?

C’est exactement ce qui se passe en informatique.

D’un côté on a des demandes du marché pour des profils qui font plus.

De l’autre on a des filières qui mettent sur le marché des gens qui ne font rien.

En même temps, on n’est pas près à payer ceux qui ont les compétences au juste prix, et les grosses boîtes comme Google, Facebook, Microsoft, Yahoo, Instragram, Twitter, etc. raflent tout.

Il ne reste plus rien.

Je résume :

Voilà la situation aujourd’hui.

Et j’entends encore des devs qui me disent qu’ils ne trouvent pas du boulot.

Et ça m’énerve !

Il y a d’abord le mec, qui ne veut pas bouger, pas changer de technos, pas se mettre à jour, et cherche une fois par mois de la même façon que le faisait sa grand-mère.

Il y a la meuf qui est dans le fond de la creuse sur un modem 56k et qui ne comprend pas que les starts up ne frappent pas à sa porte.

Ceux qui ont 3 enfants et qui ne peuvent pas. Peuvent pas quoi, je ne sais pas, mais ils peuvent pas. Ceux qui envoient des CV et n’appellent jamais. Ceux qui arrivent à l’entretien d’embauche avec des miettes dans la barbe. Ceux qui attendent chez eux qu’un miracle arrive alors qu’ils ont 15 évènements de réseautage dans leur inbox…

Bref, non seulement le marché est déséquilibré, mais une partie du vivier s’assure activement de rester inaccessible à l’embauche.

En plus — merde ! — le dev c’est quand même un des métiers les plus permissifs du monde.

Tu es en chaise roulante ? Cool des aides.

Tu as des piercings ? Ranafout.

Tu as la capacité sociale d’une moule ? On s’arrange.

Tu veux bosser chez toi ? Ça se négocie.

Alors je ne dis pas que tout le monde embauche. Je ne prétends pas qu’il suffit de se balader avec une pancarte dans la rue avec marqué « échange COBOL contre soussous » pour faire fortune.

Mais tout de même, on est sur le marché le plus florissant du monde. Faites péter le champagne !

Et si vous êtes recruteurs, préparez-vous à devenir attractif. Car vous risquez fort de vous retrouver uniquement avec le fond du panier, et à remercier le ciel qu’on vous en ait laissé.

Or la compétitivité d’une boite dépend aujourd’hui tout autant de sa vitrine IRL que de celle en ligne. Et le prix du ticket d’entrée du service minimum a pris une sacrée inflation. J’ai vu cette semaine une meuf s’enerver qu’un site ne marchait pas parce que la barre de recherche n’avait pas de résultat live : il fallait appuyer sur le bouton pour avoir les résultats.

Tirez-en la conclusion que vous voulez, mais tirez-la vite.

Vous n’avez pas besoin de nous demander 4

lundi 21 décembre 2015 à 11:51

Aujourd’hui, on nous a demandé la permission, par mail, de réutiliser un de nos schémas pour un article.

C’est très gentil de demander, mais vraiment ne vous embêtez pas avec ça.

Tout le blog, sauf mention spécifique explicite, est sous licence Creative Common Unported. Vous pouvez donc prendre notre contenu et le publier ailleurs, le modifier, et même le vendre. Et vous ne nous devez rien.

La seule obligation, c’est de citer la source : mettez un lien vers le blog à côté de ce que vous réutilisez.

C’est tout.

Donc inutile de nous écrire pour nous piquer un truc. Pillez mes amis, pillez.

On a tenté de nous hacker 0bin 7

dimanche 20 décembre 2015 à 10:36

En me baladant dans l’arbo de 0bin.net pour retirer un dox qu’on m’avait signalé je suis tombé sur un dossier au nom bizarre :

# ls -l
total 4
4 drwxr-xr-x 7 root root 4096 sept. 24  2014 --

Hum, voilà qui n’est pas pratique à analyser depuis le bash. Et pourquoi j’ai ce dossier-là d’ailleurs ?

Regardons ce qu’il y a dedans :

# python -c "import os; os.rename('--', "strange_dir")"
# ls strange_dir/
3Q  Dk  k5  Oh  -u

Oh, y a un dossier nommé “-u”…

A ce stade-là, j’ai juste supprimé le truc.

Et j’ai réalisé : on crée les dossiers de l’arbo en fonction du nom du paste, qui est une clé générée côté client, et donc fournie par un code JavaScript non trusté.

Du coup l’attaqueur nous a sans doute passé une commande bash comme nom de fichier. J’imagine, espérant qu’on fabriquait le fichier avec une exécution shell. Comme on utilise le module os pour le faire, je pense que ça n’a eu aucun impact.

J’espère :)