Licence CC BY

[Réaction]Programmation orientée objet, qu'est-ce que c'est

Discord a trouvé un article de futura science...

Aujourd’hui, je vais tester quelque chose: réagir à un article écrit par des journalistes sur un sujet technique.

Sur discord, des gens ont un peu ricané lorsque la section "Futura Tech" du site futura-sciences a publié un article nommé "Programmation orientée objet: qu’est-ce que c’est".

La plupart de nos réactions étaient négatives, mais je me suis dit qu’on pouvait quand même tirer quelque chose de tout ça, notamment un débat sur ce que c’est ou ce que n’est pas la POO.

Ma réaction va être biaisée, mais je peux déjà vous dire qu’elle le sera à cause de quelque chose de très précis : mon propre apprentissage de la POO a été marqué par deux événements. D’un côté, un cours particulièrement chiant, mais où l’enseignant a réussi à montrer l’importance capitale du principe de responsabilité unique et pourquoi la composition était plus importante que l’héritage, de l’autre une conférence d’un des créateurs de Small Talk qui encensait JavaScript pour être (de mémoire) "le langage à la POO la plus pure".
Vous avez le décors.

Définition de la POO

Commençons par les présentation :

La programmation orientée objet est une méthode de programmation informatique de plus en plus plébiscitée, que ce soit dans le développement logiciel ou la data science.

Ah. C’est vrai ou pas au moins ça? Depuis le temps qu’on nous dit que la POO est dépassée, je me demande si vraiment elle est de plus en plus utilisée?

Surtout quand je vois à quoi un playbook jupyter de data-science ressemble, je me dis qu’en fait cette affirmation est un peu désuette.

D’ailleurs, on y reviendra plus tard mais un des langages qui fait de la concurrence à python dans les data science c’est go, @nohar vous donnera sûrement un avis plus éclairé que le mien, mais en fonction de comment on définit "La POO", on ne répondra pas toujours la même manière à la question "Go est il un langage objet".

D’ailleurs, c’est probablement là qu’est le soucis quand on présente la POO et comment la faire : vu le nom on se doute que la POO est une manière de programmer avec des objets. Mais c’est quoi un objet?

Un objet

L’article a une réponse à vous apporter :

On appelle objet, un ensemble de variables complexes et de fonctions, comme par exemple un bouton ou une fenêtre sur l’ordinateur, des personnes (avec les noms, adresse…), une musique, une voiture…
Presque tout peut être considéré comme un objet.

Si avec ça vous avez compris, bravo à vous.

Outre la construction de la phrase, elle ne vous dit clairement pas ce qu’est un objet dans le domaine de l’informatique. Parce que bon, étaler les synonymes de objets (babioles, trucs, bidules…) ça ne vous apprend rien.

Heureusement, l’auteur a pensé à vous et va vous donner la clef de compréhension :

La première [étape de la POO] consiste à modéliser les données en identifiant les objets que le programmeur souhaite manipuler ainsi que leurs interactions.

Vous savez toujours pas ce que sont les objets, mais vous savez qu’ils interagissent et c’est c’est beau.

Je me moque, mais si on se rappelle de mon disclaimer de début d’article, c’est en effet primordiale. Je vais donc vous donner une première définition personnelle de la POO.

Première définition personnelle

La programmation orientée objet consiste à extraire du besoin fonctionnel les intéractions entre les différentes entités prenant partie au programme : une interface avec l’humain, une source de données, un algorithme à exécuter. Une fois ces intéractions extraites on les modélises dans des briques logicielles ayant une responsabilité unique et déléguant le reste de l’algorithmes aux entités qui l’entourent.

C’est encore assez vague, mais après avoir écrit cette phrase, j’ai décidé d’aller sur wikipédia, et j’ai vu ça :

La programmation orientée objet (POO), ou programmation par objet, est un paradigme de programmation informatique. Elle consiste en la définition et l’interaction de briques logicielles appelées objets ; un objet représente un concept, une idée ou toute entité du monde physique, comme une voiture, une personne ou encore une page d’un livre.

Il possède une structure interne et un comportement, et il sait interagir avec ses pairs. Il s’agit donc de représenter ces objets et leurs relations ; l’interaction entre les objets via leurs relations permet de concevoir et réaliser les fonctionnalités attendues, de mieux résoudre le ou les problèmes. Dès lors, l’étape de modélisation revêt une importance majeure et nécessaire pour la POO. C’est elle qui permet de transcrire les éléments du réel sous forme virtuelle.

On remarquera que les exemples évoqués par futura ressemblent à la partie "entité du monde physique" de cette définition.

D’ailleurs je me dis que le plus gros problème de la définition de futura c’est qu’elle fait l’erreur d’isoler "objet" pour tenter de retomber sur ses pieds. Mais finalement que ça soit du côté de wikipédia ou de ma définition, ce qui importe c’est qu’on programme et qu’on va juste concevoir notre programme pour mettre en avant des intéractions. C’est pour ça que des choses très abstraites apparaissent.

Je pense que la plus gros indice qui va dans le sens de cette analyse c’est cette phrase :

Une fois l’objet créé, il communique avec une interface bien définie appelée message.

J’ai reproduit le texte et la mise en forme pour montrer combien l’article se méprend : il confond interface homme/machine, interface qui définit les intéractions entre objets (et souvent déclaré avec le mot clef interface tout est lié) et message qui a tellement de sens en informatique que je me demande vraiment si on est toujours dans le sujet de la POO.

Encapsulation, et pensée OO magique

(pensée oO : vous l’avez?)

Si vous n’avez toujours pas compris ce qu’était la POO, ne vous inquiétez pas, peut être que finalement ce qui est intéressant, c’est à quoi ça sert.

Avant de passer à la réponse (qui est le seul truc choquant de l’article en fait, le reste n’est qu’approximations qu’on peut comprendre quand on essaie de présenter des choses ultra techniques à des non techniques) lunaire de futura-sciences, je vous propose la mienne :

  • Tester les programmes plus facilement;
  • Travailler plus facilement en équipe, car tout en restant technique on peut facilement s’exprimer dans un langage naturel pour transmettre la connaissance;
  • Réutiliser des blocs de codes plus larges entre les projets qu’avec le paradigme dont la POO hérite : le procédural.

Les commentaires du billets sont ouverts pour donner d’autres intérêt si vous en avez ou nuancer ceux que j’ai proposés.

Trêve de teasing, qu’en dit futura?

En masquant les fonctions et variables de l’objet, le programmeur crée un code source parfois complexe mais facilement utilisable, tout en renforçant la sécurité du système et en évitant la corruption accidentelle de données. Grâce à ses propriétés d’héritage et de polymorphisme, une classe est réutilisable par le programme pour lequel elle a été créée, mais aussi par d’autres programmes orientés objet.

  • La complexité d’un programme ne dépend casi pas du paradigme.
  • La réutilisabilité est selon moi en effet augmentée, mais encore faut-il savoir réutilisable par qui?.
  • LA POO NE PERMET PAS D’AUGMENTER LA SECURITÉ NI LA ROBUSTESSE FACE AUX CORRUPTIONS, MERCI.
  • Alors la réutilisabilité d’une classe n’est que peu corrélée au polymorphisme selon moi (ou alors il faut se faire des noeuds aux cerveau pour lier le polymorphisme à la réutilisabilité).
  • Si votre langage le permet une fonction isolée est tout aussi réutilisable qu’une classe, même dans des autres programmes.

Outre la grosse erreur sur la sécurité, en fait ces "intérêt" sont globalement non pas les intérêts de la POO mais les intérêt d’un programme conçu pour être développé par plusieurs personnes sur le temps long. Il va donc falloir créer des bouts de codes réutilisables partout, des moyens de communiquer, des tests… La POO permet d’avoir un outillage pour ça, mais le procédural ou le fonctionnel aussi.

Les concepts clés

Avant de partir, Futura nous donne une liste de six concepts clés de la POO:

  • La classe
  • Les objets
  • L’encapsulation
  • L’abstraction
  • L’héritage
  • Le polymorphisme

C’est là que la conférence "le JS est la forme la plus pure de POO" a son impact sur moi. A l’époque de cette conférence le JS possédait en effet un module orienté objet mais la notion de classe n’existait pas.

Si on se fie à l’article cela signifie que le JS ne pourrait donc pas profiter de l’encapsulation, de l’abstraction (très mal définie dans l’article, au demeurant), d’héritage ou de polymorphisme.

Alors qu’en fait… à cette époque JS avait tous les concepts sauf… les classes.

Car finalement ce qui compte, je pense, ce ne sont pas ces concepts clés là mais :

  • Définition des modes d’intéraction : chaque "objet" définit la manière dont il peut être manipulé par les autres. Cette "manière d’être manipulée" est une simple liste d’ordres qu’on peut transmettre à l’instance d’un objet. Tous les objets qui sont capables de répondre à une liste d’ordres données peuvent être utilisés tels quels dans les différents algorithmes.
  • Notion d’instance: Une instance c’est un objet avec un état donné. C’est lui qui "répondra aux ordres".
  • Délégation et composition: Chaque objet n’est capable de faire qu’exécuter ses ordres à lui, mais peut dépendre d’autres objets pour fonctionner.

Un exemple?

Ce billet commence déjà à s’éterniser alors que l’article de futura science était très court. Pourtant j’ai envie de vous donner un exemple fictif de POO qui permettra de montrer ma vision de la chose.

Énoncé

Notre but est de simuler un monde où des gens vont acheter des objets à des marchands.

Pour des raisons de sécurités évidentes, dans ce monde où la corruption et la délinquance font des ravages, il a été décidé que le paiement ne se ferait jamais face à face mais avec un programme (le notre donc).

Le programme doit donc être capable de prendre le paiement de l’acheteur et de l’acheminer jusqu’au vendeur.

Cependant, il est à noter que le vendeur ne reçoit pas l’argent directement, il le met en banque. De même que l’acheteur utilise des outils tels qu’une carte de paiement ou un chèque (oui ça existe encore) pour demander à la banque de payer.

Ah et dans ce monde idyllique, tout le monde n’utilise pas la même monnaie, mais l’État dans son infini sagesse nous donne le taux de change entre deux monnaies grâce à un composant logiciel qu’il a développé.

Ma conception

Il n’existe pas de "bonne réponse" à ce système, si ce n’est que comme c’est moi qui écrit le billet, je connais tous les sous-entendus de mon énoncés et donc que je me suis soit très simplifié le travail soit compliqué la tâche uniquement dans un but dialectique. Pour autant voir vos solutions m’intéresse.

pour ma part je vois notre système de paiement comme un immense tuyau où des gens capables de payer donnent de l’argent virtuel ou non à des gens capables de recevoir de l’argent.

  1. acheteur "donne" de l’argent "virtuel" à sa banque (ordre par carte bancaire/chèque)
  2. banque "donne" de l’argent à la banque de vendeur (argent réel cette fois-ci) et "prend" l’argent de l’acheteur (ligne dans le relevé de compte)
  3. banque "donne de l’argent" "virtuel" au vendeur (impression d’une ligne dans le relevé de compte)
  4. vendeur "prend" de l’argent à la banque lorsqu’il fait un retrait

Entre chaque étape de notre "tuyau", il y a quelque chose qui vient "convertir" les montants dans l’a monnaie du receveur.

Je vais donc créer quatre "ensembles d’ordres" :

// on va supposer que Devise et SommeEnDevise sont des choses qui sont natifs au système car fournies par l'état)

interface Payeur {
    // false si paiement impossible
    boolean payer (Receveur receveur, SommeEnDevise argent)
    validerPaiement(Receveur receveur, SommeEnDevise argent)
    invaliderPaiement(Receveur receveur, SommeEnDevise argent)
    PayeurReceveur intermédiaireDePaiement()
}
interface Convertisseur {
    SommeEnDevise echanger(SommeEnDevise sommeAEchanger, Devise deviseDésirée)
}
interface Receveur {
  
   recevoir (SommeEnDevise argent, Payeur source)
   validerPaiement(Receveur receveur, SommeEnDevise argent)    invaliderPaiement(Receveur receveur, SommeEnDevise argent)
   PayeurReceveur intermédiaireDePaiement()
   Devise getDevise()
}

interface OperateurPaiement {
   opérerLaTransaction(Payeur payeur, Receveur receveur, SommeEnDevise argentDepenséParAcheteur)
}

Pour moi, notre "tuyau" est un opérateur de paiement en soit : il permet à la transaction entre l’acheteur (qui est un payeur) et le vendeur (qui est un receveur).

On notera que les banques sont à la fois Payeur ET Receveur.

Le système de paiement interbanquaire est aussi un opérateur en lui-même : contrairement au système global, il n’essaiera pas de trouver l’intermédiaire de la banque.

On pourrait globalement voir ces deux systèmes ainsi :

class SystemInterbanquaire implements OperateurPaiement {
  public void opérerLaTransaction(Payeur payeur, Receveur receveur, SommeEnDevise argentDepenséParAcheteur) {       Convertisseur convertisseur = Etat.getConvertisseur();
      // pas de frais de change entre banque, pas de ça entre nous :p
      payeur.payer(receveur, argentDepenséParAcheteur);
      receveur.recevoir(payeur, convertisseur.echanger(argentDepenséParAcheteur, receveur.getDevise());
      payeur.validerPaiement(receveur, argentDepenséParAcheteur)
      receveur.validerPaiement(payeur, convertisseur.echanger(argentDepenséParAcheteur, receveur.getDevise())
  }
}

class SystèmeGlobal implements OperateurPaiement {

 public void opérerLaTransaction(Payeur payeur, Receveur receveur, SommeEnDevise argentDepenséParAcheteur) {
     // on peut en faire un attribut de classe
     // ou bien utiliser le pattern factory
     OperateurPaiement systemInterbanquaire = new SystemInterbanquaire();
     // 42 c'est pour les frais de change entre banque, faut vivre ma petite dame
     if (payeur.payer(payeur.getIntermediaire(), argentDepenséParAcheteur + 42)) {
        payeur.validerPaiement(receveur, argentDepenséParAcheteur + 42);
        payeur.getIntermédiaire().recevoir(payeur, argentDepenséParAcheteur + 42);
        systemInterbanquaire.opérerLaTransaction(payeur.getIntermédiaire(), receveur.getIntermédiaire(), argentDepenséParAcheteur();
        receveur.validerPaiement(payeur, argentDepenséParAcheteur());
      } else {
         // on invalide
      }
 }

L’exemple n’est pas parfait, et la solution trouvée demande un peu de rafinement, mais elle permet vraiment de mettre en avant les notions que j’ai proposées tout à l’heure, je pense.

Elle montre aussi ce que c’est vraiment que le polymorphisme. Notamment elle montre que peu importe que l’auteur paie par chèque ou par carte, on peut faire le même algorithme à chaque fois. La "validation" du chèque étant certes différente de la "validation" de la carte bleue, elle n’en reste pas moins une validation du point de vue du système de paiement.


12 commentaires

Tiens, pour faire le lien avec la discussion de ce matin sur l’UML. Moi je n’ai toujours pas bien compris à quoi ça correspondait, la POO, et je me dis que c’est peut-être là qu’un bon diagramme ça sert :D

Sinon, vous êtes plusieurs à dire que la POO n’est plus tant encensée que ça. Je l’ignorais, c’est un avis qui fait relativement consensus ? Pourquoi du coup ? (Moi j’étais effectivement resté sur l’idée d’il y a plusieurs années que c’êtait la panacée). Et on utilise quoi à la place ? Le procédural ? Ou j’ai l’impression une sorte de mix avec de la POO qui ne serait pas purement de la POO ?

+0 -0

Sinon, vous êtes plusieurs à dire que la POO n’est plus tant encensée que ça. Je l’ignorais, c’est un avis qui fait relativement consensus ?

C’est comme dans tous les domaines, il y a des modes et des tendances et on peut penser que la POO n’est plus autant en vogue qu’autrefois.

Et on utilise quoi à la place ? Le procédural ? Ou j’ai l’impression une sorte de mix avec de la POO qui ne serait pas purement de la POO ?

Le paradigme fonctionnel semble avoir connu une vague de popularité ces dernières années. Les langages qui sont nés ces dernières années se prétendent ouvertement fonctionnels (mais pas forcément exclusivement fonctionnel) et ne cachent pas leurs inspirations. Je pense notamment à Rust (2010) qui hérite fièrement des langages à la ML ou de Clojure (2007) qui est carrément un Lisp. On peut aussi penser à Java qui a introduit les lambdas dans le langage, fonctionnalité jusqu’à là plutôt cantonnée aux langage fonctionnels.

Évidemment, beaucoup de langages avaient déjà des traits de fonctionnel, dans le sens où il a toujours ou presque été possible d’adopter un style caractéristique du paradigme : fonction anonymes (lambda), closures, fonction en tant qu’objets de premier ordre qu’on trouve en Python, JavaScript, ou même PHP. Mais cela ne veut pas dire pour autant que les communautés respectives de ces langages approuvaient l’usage massif de ce style, alors que dans d’autres langages comme Haskell ou OCaml ça me semblait être la norme.

C’est possible de faire du Python à la Haskell en sortant functools, reduce, map, en composant tout et n’importe quoi etc. Mais ça ne serait pas considéré comme un code pythonique, dans ce cas.

Cela montre qu’au delà de ce qu’offre techniquement le langage, il y a aussi une notion d'usage à prendre en compte pour affirmer clairement « ce langage est fonctionnel ». Dans ce sens, j’ai l’impression qu’il devient de plus en plus admis d’adopter des patterns fonctionnels là où autrefois on allait privilégier un style typique de l’OO. (sans exagérer non plus)

Cependant, je n’ai pas l’impression que ça remplace la POO comme certains le pensaient/l’espéraient. J’ai plutôt l’impression que les nouveaux langages (ou grosses versions de langage) essaient de prendre le meilleur des deux mondes en faisant une sorte de mix, comme tu dis.

Je précise que ma réflexion est assez spéculative. C’est un ressenti et mes impressions sur ces dernières années.

+0 -0

, et je me dis que c’est peut-être là qu’un bon diagramme ça sert

les diagrammes UML sont parfois simples à comprendre (mais j’ai déjà mis du temps à écrire mon billet, j’avais la flemme de doubler le temps juste pour des graphes) mais ils restent un formalisme très très très abstrait. Du coup souvent on en revient au code pour comprendre le but de la conception.

Sinon, vous êtes plusieurs à dire que la POO n’est plus tant encensée que ça

Globalement, la POO, c’est un outil ultra efficace pour organiser des projets et permettre à des équipes de maintenir des projets sur le long terme. Du coup c’est encore très utilisé. Mais c’est cet aspect structurel qui est très mis en avant plus que l’aspect opérationnel. Aujourd’hui, dans l’opérationnel, c’est surtout l’expressivité qui compte. Et là les langages OO, très verbeux, vont beaucoup chercher des concepts dans d’autres paradigmes (fonctionnel notamment) pour créer des pipelines de traitement.

C’est élégant (et à ce jeu LINQ, le langage dans le langage qu’on trouve dans .NET et qui permet de manipuler des ensembles de données en mélangeant SQL et fonctionnel est vraiment le summum de l’expressivité et de l’élégance) mais on en revient toujours à l’OO quand il faut structurer, documenter, concevoir.

Les langages purement fonctionnels sont pas mal limités à des niches (haskell pour le parsing par exemple).

Pour autant pas mal de langages arrivent avec leurs organisations, leurs concepts et leurs implémentations qui chamboulent un peu tout ça.

Pendant que tout le monde cherche à mettre de l’OO en forçant au talon dans JS, des langages comme Go viennent avec des moyens de structurer le code assez KISS et c’est assez jouissif à la fin, même si en contrepartie il y a plein de pièges à éviter, mais le tooling (go vet était un ami fidèle à l’époque, je pense que ça l’est toujours) permet de détecter tous les eccueils.

Aujourd’hui, on va parler de "Data Driven Development" de ce que j’ai compris, notamment avec Go et Python. La POO de python devient alors un simple outil. Je dirais que l’intégration des Stream dans java et tout l’ajout fonctionnel qu’on a eu avec j8 et j9 est aussi dans cette veine.

Sinon, vous êtes plusieurs à dire que la POO n’est plus tant encensée que ça.

Je fais partie des gens qui disent ça, mais c’est vrai que ça mérite quelques explications.

Je l’ignorais, c’est un avis qui fait relativement consensus ?

Si on regarde les derniers langages qui sont sortis depuis 10 ans, et à quelques exceptions près (notamment côté frontend où on retrouve des langages comme TypeScript ou Dart qui sont très… classiques), on remarque une nette rupture avec les langages OO d’avant. Côté backend et système, ni Go, ni Rust, ni Zig, ni… ne reproduisent vraiment les concepts de classe ou d’héritage.

Le problème, c’est que l’on sait de longue date que l’Orienté Objet "pur" est difficile à utiliser correctement : on a d’un côté les explications de base sur l’encapsulation, le passage de messages, la composition, de l’autre des tas de règles parfois obscures (Open Closed Principle, Liskov Substitution Principle), des notions encore plus compliquées pour les expliquer (invariants, covariants, contravariants…), et depuis les années 1990, des tas de recettes de cuisine avec les Object Oriented Design Patterns. On est loin du super paradigme qu’on peut secouer comme une baguette magique au-dessus d’un problème pour le rendre facile à résoudre, qui guérit les cors au pieds et résout la faim dans le monde, que l’article de Futura Sciences nous vend : on est sur un concept qui non seulement demande de l’expérience et un long apprentissage pour le maîtriser correctement, mais qui en plus déjoue l’intuition, sans le sens où ce que les gens qui débutent vont d’abord concevoir intuitivement s’avère être le plus souvent la pire solution à un problème donné.

Depuis les années 1990, on observe que les gens qui se forment à la POO font de leur mieux avec ce qu’ils ont. Il y a 20 ans, la mode était de coller de l’héritage partout, ce qui aboutissait à d’immenses arbres de relations entre les classes… qui finissaient par se casser la figure (n’importe quel livre parlant un tant soit peu techniquement de programmation de jeux vidéo expose très vite les limites de cette approche, qui sont assez proches de ce que le Javaquarium met en évidence). Et c’est notamment pour cette raison que les langages modernes reprennent ce qui est utile de la POO (le polymorphisme par interfaces — ou traits comme les appelle Rust — par exemple) tout en prenant bien soin de se défaire des nids à poussière (l’héritage est devenu un tabou à peu près absolu, etc.).

Ce qui m’a fait personnellement grincer des dents avec l’article que cite @artragis, c’est qu’il présente la POO comme à la fin des années 90 où on vendait des langages corporate à des managers qui ne pigeaient rien à la programmation, comme si les vingt dernières années n’avaient pas eu lieu.

+3 -0

Et c’est notamment pour cette raison que les langages modernes reprennent ce qui est utile de la POO (le polymorphisme par interfaces — ou traits comme les appelle Rust — par exemple) tout en prenant bien soin de se défaire des nids à poussière (l’héritage est devenu un tabou à peu près absolu, etc.).

Un point intéressant, il est à noter que ça ne dispense pas totalement les développeurs de devoir se frotter à des notions de théorie des types. Par exemple, la notion de variance que tu mentionnes apparaît dans Rust avec les durées de vie longues qui sont vues comme un sous-type des durées de vie plus courtes qu’elles contiennent (ce qui permet d’enforcer par construction toutes les contraintes souhaitées sur les durées du vie, c’est plutôt élégant). En pratique, c’est souvent masqué, mais ça peut pointer le bout de son nez lors du développement de structure de données par exemple.

J’imagine que la seule stratégie pour se débarrasser totalement de ces considérations est soit de ne pas traiter le polymorphisme, soit avoir un système de types qui ne garantit pas grand chose d’intéressant.

+0 -0

A propos de l’OO je me permets de ressortir ça : https://zestedesavoir.com/billets/3116/causerie-episode-4/ ^^

de l’autre des tas de règles parfois obscures (Open Closed Principle, Liskov Substitution Principle), des notions encore plus compliquées pour les expliquer (invariants, covariants, contravariants…)

Autant plein de concepts sont obscures (parce que justement mal définis), autant je trouve que comprendre le LSP avec juste quelques bases en logique de Hoare (qui n’est pas très compliquée à piger), ça semble assez simple. Il faudrait que j’écrive un billet là dessus à l’occasion. Mais si tu comprends la règle d’affaiblissement en logique de Hoare, le LSP en découle de manière directe.

Comprenons-nous bien, quand je parle de truc obscurs ou compliqués à piger, je ne parle pas de moi qui me traîne pratiquement 15 ans de carrière. Je parle du point de vue des gens qui apprennent à programmer.

Typiquement le genre de gens qui seraient déroutés quand on leur parle du LSP, et encore plus quand on leur dit que c’est facile si on passe par un autre truc au nom barb-Hoare.

La cible de l’article de Futura-Science, quoi.

PS : quoique l’article semble s’adresser à des data scientists, qui, a priori, savent réagir sainement face à des notions théoriques inconnues…

+0 -0

Je parle du point de vue des gens qui apprennent à programmer.

Typiquement le genre de gens qui seraient déroutés quand on leur parle du LSP, et encore plus quand on leur dit que c’est facile si on passe par un autre truc au nom barb-Hoare.

nohar

Ben pour moi, il y a une question plus fondamentale là. Est ce que c’est normal si quelqu’un qui apprend à programmer ne reçoit pas au passage les notions théoriques de base sur lesquelles reposent le fonctionnement d’un programme ? (et je dis ça en ayant eu l’occasion de voir ces notions qu’après mon Master alors que clairement la logique de Hoare ne nécessite pas le bagage technique et théorique d’un Master).

Quelque part, doit on considérer le développement comme de l’artisanat (avec ses astuces, ses bonnes pratiques et de quelque part, amener par là une importance extrêmement forte à l’empirisme et l’expérience de l’artisan) ou comme un métier "technico-scientifique" (avec des fondements de théorique de base et qui ont une importance plus ou moins grande selon la tâche à réaliser, mais où l’on vise à remplacer au maximum l’empirisme parce des éléments tangibles) ?

Personnellement, j’ai tendance à considérer que l’on devrait plutôt viser la seconde, c’est pas un avis forcément partagé, c’est simplement en ligne avec le fait que je pense que l’on devrait au maximum être capable d’expliquer de manière mesurable pourquoi on a confiance dans la qualité de tel ou tel système (et d’indiquer nos points d’incertitude).

Quelque part, doit on considérer le développement comme de l’artisanat (avec ses astuces, ses bonnes pratiques et de quelque part, amener par là une importance extrêmement forte à l’empirisme et l’expérience de l’artisan) ou comme un métier "technico-scientifique" (avec des fondements de théorique de base et qui ont une importance plus ou moins grande selon la tâche à réaliser, mais où l’on vise à remplacer au maximum l’empirisme parce des éléments tangibles) ?

Mon point de vue c’est que ces deux aspects ne sont pas du tout mutuellement exclusifs, qu’ils se conjuguent et même se complètent dans le métier d’ingénieur en développement logiciel. En ce sens, quelqu’un qui viserait tout l’un ou tout l’autre ne pourrait pas faire un bon développeur à mes yeux.

Bref, pour moi il faut impérativement cultiver les deux et faire progresser les deux aspects, car les deux visions sont d’importance égale dans le métier.

PS : De la même manière, dans un tout autre domaine, on ne peut pas considérer le jazz comme une activité purement intellectuelle, ni purement technique, ni purement artisanale. Un bon musicien de jazz maîtrise beaucoup de théorie, et dispose d’un savoir faire et d’une intuition qu’il a cultivés avec des années de pratique : s’il n’avait pas les deux, ce ne serait pas un bon musicien. Pareil pour la médecine…

+0 -0

Ben quelque part, c’est mon point. Actuellement, j’ai l’impression (mais je peux me tromper), qu’on a tendance à tout placer à l’extrémité artisanat du spectre et qu’il manque certains fondamentaux dans l’apprentissage du développement. On enseigne des "bonnes pratiques" mais sans les recaler dans le fondement théorique de base.

Ben quelque part, c’est mon point. Actuellement, j’ai l’impression (mais je peux me tromper), qu’on a tendance à tout placer à l’extrémité artisanat du spectre et qu’il manque certains fondamentaux dans l’apprentissage du développement. On enseigne des "bonnes pratiques" mais sans les recaler dans le fondement théorique de base.

Ksass`Peuk

Je vois les choses un peu différemment.

D’un côté je partage ton observation : on enseigne des bonnes pratiques un peu comme des recettes de grand-mère. Ce qui fait s’arracher les cheveux aux gens qui connaissent la théorie.

De l’autre, on a également le phénomène opposé : les écoles d’informatique en France semblent aborder son enseignement comme si on pouvait faire des cours magistraux avec deux trois projets encadrés puis lâcher les jeunes diplômés dans la nature en considérant qu’on en a fait des professionnels compétents puisqu’ils ont bien bossé leurs cours.

Résultat, les jeunes diplômés ne maîtrisent ni la théorie (car ce n’est pas la théorie "qui importe" qui est enseignée), ni le métier (par contre ils ont des jolies connaissances théoriques sur Agile et le management de projet).

C’est pour ça que je dis qu’il ne faut pas voir ça comme un curseur à placer entre deux idéaux : que l’on se place du point de vue de la théorie comme de celui du software craftsmanship, l’enseignement du développement marche sur la tête et les pratiques des entreprises sont le plus souvent complètement à côté de la plaque.

Il y a énormément de progrès à faire des deux points de vue. Si l’aspect artisanal était si soigné que cela, on se taperait vachement moins de bloatwares et les 3/4 des blagues des "joies du code" seraient caduques.

+0 -0

De l’autre, on a également le phénomène opposé : les écoles d’informatique en France semblent aborder son enseignement comme si on pouvait faire des cours magistraux avec deux trois projets encadrés puis lâcher les jeunes diplômés dans la nature en considérant qu’on en a fait des professionnels compétents puisqu’ils ont bien bossé leurs cours.

J’ai pas des années de carrière, mais je ne pense pas avoir rencontré un seul prof dans l’académique défendant qu’un étudiant qui sort de la fac ou d’une école d’ingé est opé pour bosser immédiatement dans un milieu professionnel. Mon observation n’est pas sur la formation académique mais sur la formation "au global", c’est à dire en cumulant l’académique, l’autoformation et la formation pro fournie par la boîte où l’on bosse.

Résultat, les jeunes diplômés ne maîtrisent ni la théorie (car ce n’est pas la théorie "qui importe" qui est enseignée), ni le métier (par contre ils ont des jolies connaissances théoriques sur Agile et le management de projet).

Je vois trop souvent des collègues céder à des demandes absurdes du monde indus alors qu’ils n’ont pas les compétences pour assurer ces cours :( . Sans parler de ceux qui cèdent à "dernière techno à la mode" alors qu’ils savent pertinemment qu’ils n’ont pas le temps de produire un nouveau cours dessus.

Il y a énormément de progrès à faire des deux points de vue. Si l’aspect artisanal était si soigné que cela, on se taperait vachement moins de bloatwares et les 3/4 des blagues des "joies du code" seraient caduques.

J’ai dit qu’on se focalisais dessus, pas qu’on le faisait bien :D

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte