memo YAML

Respecte l’indentation (uniquement via les espaces)

  • avec [ pour les listes
  • : avec { pour les mappings (enregistrements / tableau associatifs)

Pour le multi-ligne c’est un peu compliqué (_ veut dire espace):

  • | et > démarre à la ligne suivante, garde les espaces à la fin
    • | considère les sauts de ligne comme des sauts de ligne et pas des espaces
  • _ et et «  sur la même ligne, élimine les espaces à la fin
    • «  échappe les \n et \ et « 
    • _ si la chaîne ne contient pas # ou :
Scalars
# scalar = value
a: 1
a: 1.234
b: 'abc'
b: "abc"
b: abc
c: false	# boolean type
d: 2015-04-05	# date type

# Enforcing strings
b: !str 2015-04-05
Sequences
# sequence
array:
- 132
- 2.434
- 'abc'

# sqeuence of sequences
my_array:
- [1, 2, 3]
- [4, 5, 6]
Hashes
# Nest hash
my_hash:
  subkey:
    subsubkey1: 5
    subsubkey2: 6
  another:
    somethingelse: 'Important!'

# Hash of hashes
my_hash: {nr1: 5, nr2: 6}
Newlines
# block notation (newlines become spaces)
content:
  Arbitrary free text
  over multiple lines stopping
  after indentation changes...

# literal style (newlines are preserved)
content: |
  Arbitrary free text
  over "multiple lines" stopping
  after indentation changes...

# + indicator (keep extra newlines after block)
content: |+
  Arbitrary free text with two newlines after


# - indicator (remove extra newlines after block)
content: |-
  Arbitrary free text without newlines after it


# folded style (plié newlines are preserved)
content: >
  Arbitrary free text
  over "multiple lines" stopping
  after indentation changes...

Multiple Documents
---
content: doc1
---
content: doc2
Reference Content
---
values:
- &ref Something to reuse
- *ref	# Reused content
Merging Keys
default_settings:
  install:
    dir: /usr/local
    owner: root
  config:
    enabled: false

# Derive settings for 'my_app' from default and change install::owner
my_app_settings:
  <<: *default_settings
  install:
    owner: my_user
Complex Mapping
---
? - key
:
  - value
# Note: key and value can be multiple, complex structures
Tags
%TAG !personne! tag:foo.org,2004:bar
---
- !personne
    nom:    Simpson
    prenom: Omer
explicit_string: !!str 0.5
python_complex_number: !!python/complex 1+2j

Mémo pour les sautes de ligne

> | _ «  >-
Trailing spaces Kept Kept Kept
Single newline => _ \n _ _ _ _
Double newline => \n \n\n \n \n \n \n
In-line newlines No No No \n No No
Appended* \n \n \n
Single quote  »
Double quote «  «  «  \ » «  « 
Backslash \ \ \ \\ \ \
 » # », « : «  Ok Ok No Ok Ok Ok
Can start on same line as key  No No Yes Yes Yes No
  • http://symfony.com/legacy/doc/reference/1_3/fr/02-yaml
  • http://www.yaml.org/refcard.html
  • http://lzone.de/cheat-sheet/YAML
  • https://fr.wikipedia.org/wiki/YAML
  • http://sweetohm.net/article/introduction-yaml.html
  • http://stackoverflow.com/questions/3790454/in-yaml-how-do-i-break-a-string-over-multiple-lines
  • http://learnxinyminutes.com/docs/yaml/

Les plugins de Drupal 8, kaçaçéksa ?

En Drupal 7, tout démarre avec le hooks. Ce temps de simplicité se termine avec Drupal 8, on a maintenant 6 mécanismes d’extension (hooks, plugins, entities, services, routing, events). Les plugins sont les petits nouveaux de l’API drupal 8, ils remplacent certains hooks, mais pas tous. On y est très vite confronté puisque pour créer un block, on passe par un plugin (Drupal\Core\Block\BlockBase). Mais pas pour créer un menu menu (hook_menu qui n’existe plus en Drupal 8) ni modifier une formulaire (hook_form_alter, qui existe toujours en D8). Pourquoi ?

Pourquoi certains hooks sont remplacés et pas d’autres ? Pourquoi les avoir remplacés ? hook, plugin, services, avec tous ces mécanismes d’extensions, on s’y perds. Qui sert à quoi ? Je me suis très tôt posé des questions la dessus (cf mon commentaire). Avec la sortie de la RC1 et l’amélioration de la documentation, on commence à y voir plus clair.

Plugin vs Service :

Les plugins sont des extensions, des rajouts. Les services ce sont plutôt l’accès aux « internals ».

  • le cache est un service parce qu’on s’attend toujours au même comportement, quelque soit l’implémentation (base, mémoire, fichier…)
  • le widget est un plugin parce que si ils ont tous une API commune, ils se comportent très différemment les uns les autres

Plugin vs Hook:

Pour faire simple, les plugins remplacent les « hook_info ». L’avantage est double :

  1. regrouper différents hooks au sein d’une même classe. Comme le hook_block_info, le hook_block_view and so on …
  2. disposer grâce à l’héritage d’une implémentation par défaut : on ne code que ce dont on a vraiment besoin.

Notez que les hook_alter en revanche sont conservés.

Mais ou est la liste des plugins alors ? On ne l’a pas sur la page l’API plugin qui se borne à expliquer comment créer/utiliser des plugins.

Il y a une astuce : tous les plugins sont des classes annotées. Il faut aller chercher dans la liste des annotations. Autre solution, installer le module Plugin qui vous fait la liste dans Drupal lui même (mais attention, il faut installer avant le composer_manager sinon vous risquez d’avoir des soucis).

Et maintenant comparons à la liste des hook_info de Drupal 7. Je l’ai remis un peu en forme en deux colonnes pour qu’on voie mieux ce qui a été conservé et ce qui a bougé. Il y a pas mal de différences :

Drupal 8

Drupal 7

Action

hook_action_info

AggregatorFetcher

hook_aggregator_fetch_info

AggregatorParser

hook_aggregator_parse_info

AggregatorProcessor

hook_aggregator_process_info

Archiver

hook_archiver_info

Block

hook_block_info

hook_cron_queue_info

hook_element_info

CKEditorPlugin

Condition

ConfigEntityType

Constraint

ContentEntityType

ContextDefinition

DataType

DisplayVariant

Editor

EntityReferenceSelection

EntityType

hook_entity_info

FieldFormatter

hook_field_formatter_info

FieldType

hook_field_info

hook_field_storage_info

FieldWidget

hook_field_widget_info

conservé

hook_filetransfer_info

Filter

hook_filter_info

conservé

hook_hook_info

FormElement

ImageEffect

hook_image_effect_info

ImageToolkit

ImageToolkitOperation

InPlaceEditor

LanguageNegotiation

hook_language_negotiation_info

conservé

hook_language_types_info

hook_node_info

hook_openid_discovery_method_info

hook_openid_normalization_method_info

Mail

MigrateDestination

MigrateProcessPlugin

MigrateSource

PageDisplayVariant

Plugin

PluginExample

PluginID

QueueWorker

RenderElement

RestResource

SearchPlugin

hook_search_info

hook_system_theme_info

conservé

hook_token_info

hook_trigger_info

conservé

hook_updater_info

module_hook_info

Tip

Translation

ViewsAccess

ViewsArea

ViewsArgument

ViewsArgumentDefault

ViewsArgumentValidator

ViewsCache

ViewsDisplay

ViewsDisplayExtender

ViewsExposedForm

ViewsField

ViewsFilter

ViewsJoin

ViewsPager

,

ViewsQuery

ViewsRelationship

ViewsRow

ViewsSort

ViewsStyle

ViewsWizard

Conclusion :

  • la plupart des hooks_infos sont en effet transformés en Plugins, une poignée a du changer de place (ou ne plus être utile) sauf OpenID qui a été retiré du coeur.
  • Il y a pas mal de petits nouveaux dans Drupal 8, notamment tous ceux qui concernent Views (normal puisque ce module a été intégré au coeur !)
  • Un peu de refactoring coté Entité, ce qui inclus la disparition du hook_node_info (remplacé par l’entity_api. Cf l’exemple du module « example »).

 

Amoureux de Behat

Je viens de passer une semaine à coder des tests behat pour un projet Drupal !

J’en suis tombé amoureux. C’est vraiment l’outil qui manquait pour rédiger des tests : les simpleTest et compagnie, trop complexe à écrire. Cette fois, c’est aussi simple qu’écrire une phrase de base en anglais, et ça marche !

La première fois que j’en ai entendu parler, j’ai négligé Behat parce que je trouvais ça « trop magique pour être vrai ». Et bien non ! Ca fonctionne, et même bien. Et la courbe d’apprentissage est carrément raisonnable. Votre premier test peut s’écrire rapidement, et ensuite vous rentrez dans les subtilités au fur et à mesure des besoins. Le seul bémol peut-être : la doc n’est pas encore très mature.

Combiné à gitlab-ci pour automatiser les tests de non régression lors d’un merge request : que demande le peuple ?

Perl 6 est enfin sorti !!

Ça y est ! Perl 6 est sorti ! Incroyable mais vrai. Et, sur le papier du moins, l’attente en valait la peine.

Je n’ai jamais codé en perl, mais, si j’ai l’occasion je compte bien m’y essayer, essentiellement pour deux raisons :

  • méta-programmation : on peut définir Lua ou Python comme sous langages de « perl6 » !
  • programmation réactive : une fonction est déclenchée automatiquement quand une variable est modifiée

Bien sûr, il y a tout le reste, programmation object/fonctionnelle.

Cela fait des années que je surveille les les langages avec méta-programmation. Les derniers qui m’ont séduits sont Dao et Nim, ainsi que Red.

Red est une reprise de Rebol en open-source. Intéressante mais pas encore mature. Dao serait sympa, mais la communauté est plus que limitée, il ne semble pas prendre son envol. Nim en revanche fait le buzz mais semble un peu complexe, quoi que puissant.

Perl 6 se rajoute donc à la liste. Toute la question est de savoir s’il est facile à apprendre, et … à lire : avoir un langage très puissant c’est intéressant, mais si seul l’expert qui a codé peut relire son code tellement c’est ésotérique ça ne sert pas à grand chose. C’est pour cela d’ailleurs que c++ reste marginal par rapport au C : bien que plus puissant, pour comprendre le code des autres, il faut avoir investit beaucoup de temps. Quand un gars fait des héritages multiples de classes abstraites génériques (templates) on se prends vite la tête 😉

A voir donc si Perl 6 réussi à faire sa place : quand est-ce qu’on recode Drupal en perl ? lol

Drupal 8 Outils du développeur

Comme en témoigne mon petit module hello world, l’API et l’architecture de Drupal 8 sont autrement plus complexe que celle de Drupal7.

Tout programmeur est amené a se poser la question : si je me trompe, comment vais-je debugger mon code ?

Drupal 7 se base sur certains principes fondamentaux simples et universel : les hooks (qui sont des sortes de callbacks améliorées, reproduisant en PHP une forme d’AOP), les tableaux associatifs (et rarement des objets). La plupart des cas sont réglés par un bon vieux « dsm » (du module « devel » qui reste toujours présent dans Drupal 8) qui permet d’afficher le contenu de n’importe quelle variable, façon « krumo » :

Si cette méthode reste valable en Drupal 8, elle peut se révéler trop rudimentaire. Quand on se trompe de nom de classe à hériter ou d’annotation, un dsm ne nous sauvera pas. Il va nous falloir d’autres outils. Je vous en présentes ici les plus utiles.

Composer mananger

Pour l’installer il y a plusieurs étapes :

drush en -y composer_manager
drush composer-manager-init
cd core
composer drupal-update

Permet de lister les packages installés et leurs versions.

Pour rentrer dans les entrailles de la bête :

vim core/vendor/composer/autoload_classmap.php

 

 

Quelques articles sur les problèmes de dépendances (quand 2 composants dépendent de 2 versions différentes d’une même librairie):

Je mentionne le Composer extension pour drush (pas trop compris l’intérêt) : https://drupal.org/project/composer

Petit exemple pour rajouter une dépendance à son module : mymodule/composer.json [attention il faut rajouter composer.json & le champ name est important pour être reconnu par composer manager]

{
  "name": "drupal/mymodule",
  "description": "An automaticcaly generated module",
  "license": "GPL-2.0+",
  "require": {
    "acquia/acquia-sdk-php-cloud-api": ">=0.9.0,<0.10.0",
    "monolog/monolog": "1.10.*"
  }
}

Plugin

Permet de lister les plugins au sens Drupal (eq. hooks regroupés en objets) – ne fonctionne plus à l’heure actuelle en beta12.

Le Web Profiler

Indispensable. C’est un outil qui vient de symfony2 et qui a été adapté à Drupal8.

Pour installer le web-profiler, actuellement (en béta7) il faut suivre plusieurs étapes. En effet, certains modules ne s’installent pas correctement si les dépendances « internes » (packages s2) ne sont pas résolues :

  • Installer drush 7.x
  • Installer le Composer Manager
  • Rafraîchir les dépendances :
    • drush composer-manager-init
    • /core composer drupal-update
  • Installer le WebProfiler

Drupal8 debug1

Le console logger

  • Installer le module « Consoller logger »
  • Lancer la console : drush runserver 2> /dev/null
  • Écrire dans la console : file_put_contents("php://stdout", sprintf("test"));

Debug Twig

  • Activer le debug Twig : sites/default/services.yml
  • {{ dump(text) }}
  • \Doctrine\Common\Util\Debug::dump($votreCollection);

La console Drupal

Semblable à la console symfony2, mais pour Drupal. Permet de générer des modules à la volé, d’avoir un canevas.

Pour l’installer :

curl -LSs http://drupalconsole.com/installer | php

exemple d’utilisation :

./console.phar generate:module

Generator UI

Similaire a la console, mais dédié à la génération de modules. Dispose de plus de templates que la console, mais pourrait être fusionné avec à terme :

Drupal8 - generator UI

Le module upgrader

Permet d’upgrader automatiquement un module drupal 7 en 8. Pour l’installer

drush dl drupalmoduleupgrader

cd drupalmoduleupgrader

composer update

drush en -y drupalmoduleupgrader

 

Transformer un drupal7 mono-site en multi-site avec des sous-répertoires

Voici la manière de transformer un drupal monosite en drupal multisite, sous la forme :

http://www.monsite.fr qui devient http://www.monsite.fr/site1 et http://www.monsite.fr/site2
(et non pas http://site1.monsite.fr et http://site2.monsite.fr – autre cas qui n’est pas traité ici).

1/ La conf d’apache
après le « DocumentRoot » du serveur :
Alias /site1 /var/www/drupalroot
Alias /site2 /var/www/drupalroot

bien entendu, il faut mettre le bon répertoire, celui qui pointe sur la racine de Drupal

2/ le fichier .htaccess dans /var/www/drupalroot
# site1 site
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/site1/(.*)$
RewriteRule ^(.*)$ /site1/index.php [L,QSA]

# site2 site
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/site2/(.*)$
RewriteRule ^(.*)$ /site2/index.php [L,QSA]

# default site
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]

3/ le répertoire « sites »
à la racine de drupal faire:

cd sites
mv default localhost.site1
mkdir localhost.site2
ln -s localhost.site1 site1
ln -s localhost.site2 site2
cd site2
mkdir files
cp ../site1/settings.php
cp ../site1/default.settings.php
chmod 777 files settings.php

cd .  #la racine de Drupal
ln -s . site2
ln -s . site1

4/ le fichier sites.php
ici c’est un peu étrange, mais c’est « Drupal » :  http://www.monsite.fr/site2 et  http://www.monsite.fr/site1 doivent s’écrire  www.monsite.fr.site1 et  www.monsite.fr.site2
On enlève le http, et le / devient un .

<?php
$sites = array(
"www.monsite.fr.site1" => "site1",
"www.monsite.fr.site2" => "site2",
);

changer le base_url dans sites/site1/settings.php
$base_url = ‘https://www.monsite.fr/site1‘;

A ce stade l’ancien site doit fonctionner sous la nouvelle URL, mais le nouveau n’est pas encore prêt

5/ création de la nouvelle base
créer une nouvelle base de donnée vierge : site2_dev

6/ fichiers sites/site2/settings.php

$base_url = ‘https://www.monsite.fr/site2‘;
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'site2_dev',

(Attention, dans le cas présent, on est en multibase, d’ou les 2 ‘default’ qui s’enchainent)

7/ installer drupal pour créer la base
https://www.monsite.fr/site2/install.php
suivre les étapes « bêtement ».

Sinon on peut tenter un drush :

drush si ftv_site1_back --notify -y --db-url=mysql://$username$:$password$@localhost/site2_dev --account-mail=admin@local.host --account-name=admin --account-pass=$passwordadmindrupal$

et voila ! normalement à ce stade, vous avez un copie du site fonctionnellement, sans données dedans.

Drupal duel : Drupal 7&8 side by side

Voici, mis cote à cote 2 modules hello-world en Drupal 7 et Drupal 8 (beta9) qui mettent en œuvre les concepts principaux qu’on retrouve dans la plupart des modules :

  • menus et chemins d’accès
  • création de block
  • création d’un formulaire
  • theming
  • accès aux « variables »

Comme vous pouvez le constater, les changements sont nombreux, mais au final :

  • c’est la même chose écrit différement (pour simplifier : on passe du fonctionnel à de l’objet)
  • si on omet les « namespaces », ce n’est pas foncièrement plus verbeux, mais le code est éclaté en 7 fichiers en Drupal8 au lieu de 3
Drupal7 Drupal8

hello.info

hello.info.yml

name = Hello world
description = Minimalist Hello World in Drupal 7
package = Example modules
core = 7.x
files[] = hello.module
name: Hello World
type: module
description: Minimalist Hello World in Drupal 8
package: Example modules
core: 8.x

hello.module

function hello_menu() {

hello.links.menu.yml

$items['helloworld'] = array(
  'title' => 'Hello world',
hello.main:
  title: Hello world
  route_name: hello.world
$items['admin/config/content/hello'] = array(
  'title' => 'Hello config',
hello.form:
  title: Hello config
  route_name: hello.form

hello.routing.yml

$items['helloworld'] = array(
  'page callback' => '_page_hello_world',
  'access callback' => TRUE,
hello.world:
  path: 'helloworld'
  defaults:
    _controller: '\Drupal\hello\Controller\HelloRouteController::index'
  requirements:
    _access: 'TRUE'
$items['admin/config/content/hello'] = array(
  'page callback' => 'drupal_get_form',
  'page arguments' => array('hello_config_form'),
  'access arguments' => array('access hello content')
hello.form:
  path: 'admin/config/content/hello'
  defaults:
    _form: '\Drupal\hello\Form\HelloForm'
  requirements:
    _permission: 'access hello content'
function hello_theme() {
  return array(
    'hello_text' => array(
    'template' => 'hello-text',
    'variables' => array('text' => NULL)),
  );
}
function hello_theme() {
  return array(
    'hello_text' => array(
    'template' => 'hello-text',
    'variables' => array('text' => NULL)),
  );
}

src/Controller/HelloRouteController.php

function _page_hello_world() {
  return array( '#markup' => '<p>Hello world page text</p>' );
}
namespace Drupal\hello\Controller;
use Drupal\Core\Controller\ControllerBase;
class HelloRouteController extends ControllerBase {
  public function index() {
    return array('#markup' => '<p>Hello world page text</p>');
  }
}

src/Plugin/Block/HelloBlock.php

function hello_block_info() {
  $blocks['hello'] = array(
    'info' => t('Hello world block title'),
  );
  return $blocks;
}
namespace Drupal\hello\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\block\Annotation\Block;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Session\AccountInterface;
/**
* Provides a 'Hello' block.
* @Block(
* id = "hello_block",
* admin_label = @Translation("Hello world block title")
* )
*/
function hello_block_view($delta = '') {
  switch ($delta) {
    case 'hello':
      $block['subject'] = t('Hello world');
      $block['content'] = theme('hello_text', array('text' => 
        variable_get('hello_value', 'hello')));
      break;
  }
  return $block;
}
class HelloBlock extends BlockBase {
  public function build() {
    return array('#theme' => 'hello_text', '#text' =>
      \Drupal::config('hello.settings')->get('hello_value'));
  }
}

src/Form/HelloForm.php

function hello_config_form() {
namespace Drupal\hello\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class HelloForm extends FormBase {
  public function getFormID() {
    return 'hello_form';
  }
  public function buildForm(array $form, 
    FormStateInterface $form_state) {
  $form['hello_config'] = array(
    '#type' => 'textfield',
    '#title' => t('Who are you ?'),
    '#size' => 10,
    '#description' => t('Text for the hello world block.'),
    '#default_value' => 
       variable_get('hello_value', 'anonymous'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}
  $form['hello_config'] = array(
    '#type' => 'textfield',
    '#title' => t('Who are you ?'),
    '#size' => 10,
    '#description' => t('Text for the hello world block.'),
    '#default_value' => 
       \Drupal::config('hello.settings')->get('hello_value'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}
function hello_config_form_submit($form, $form_state) {
  variable_set('hello_value', 
    $form_state['values']['hello_config']);
}
public function submitForm(array &$form, 
  FormStateInterface $form_state) {
  $form_values = $form_state->getValues();
  \Drupal::service('config.factory')->getEditable('hello.settings')
->set('hello_value', $form_values['hello_config'])
->save();
}

drupal7-hello-world/hello-text.tpl.php

Hi from template : <?php print $variables['text']; ?>
Hi from template : {{ text }}

 

Wolfram Language : affaire à suivre

Après Mathematica, Wolfram Alpha (le moteur de recherche qui comprends les questions), après « A New Kind of Science » et son approche empirique et systématique des automates cellulaires, Wolfram Langage impressionne !!!

  • Syntaxe simple, à la Rebol/Lisp/4th/Logo.
  • Connection a Wolfram Alpha, et donc à un Big Data universel
  • Cloud, déployable, parallélisable (sur une ferme de RPi par exemple)

Cela semble être le GRAAL des programmeurs, toutes les meilleurs idées regroupées en un seul langage. Seul défaut, il n’est pas open-source.

En quelques lignes on peut calculer le plus court trajet pour parcourir les capitales Européennes, demander l’heure de couché du soleil locale, générer des graphes interactifs, etc…

Pourquoi et comment se former à Drupal ?

Pourquoi ?

J’ai la chance d’avoir la double casquette de chef de projet et formateur Drupal.

J’ai pu constater « de visu » les dégâts que peuvent faire de mauvaises pratiques sur un développement Drupal.

Par exemple, j’ai du intervenir en tant que consultant sur un projet ou l’on me demandait comment rajouter une fonctionnalité au site. Tout naturellement, j’ai conseillé d’installer un module (la manière de choisir ou pas un module est un autre sujet) qui répondait suffisamment bien à la demande. Mais là, je me suis rendu compte que le reste du site était développé de manière « non drupaliene » et que le module ne serait pas compatible avec le site.

Il ne faut pas sous-estimer la réticence des développeurs à apprendre un nouveau framework :

  • d’abord c’est un effort considérable, un investissement, qui n’est pas toujours perçu comme rentable (à juste titre parfois);
  • ensuite, il y a les goûts et les couleurs. Les choix techniques d’un framework ne sont pas toujours parfait, ni bien justifiés;
  • connaître une API c’est une chose, mais connaître les limites d’un framework, savoir contourner et anticiper les problèmes, ça demande énormément d’expérience, voire de la passion. C’est parfois plus simple de développer les choses soi même;
  • parfois aussi, Drupal n’est pas le meilleur choix, et le développeur en connaît un plus efficace (tout du moins partiellement, mais ça peut être suffisant pour ne pas avoir envie de s’investir)

Donc, les développeurs se forment parfois à contre-coeur, ou mal, ou n’ont pas le temps de le faire correctement. En tant que formateur, il faut en tenir compte. Les conséquences de l’absence de formation sont parfois (souvent) bien plus importantes que les 3 jours qu’on « perds » à les suivre.

Le ROI d’une formation sur un produit comme Drupal est très rapide.

Comment ?

Le rôle d’un formateur est multiple, mais en premier lieu il s’agit de :

  • s’assurer que tous les concepts de bases sont assimilés
  • donner un maximum d’autonomie aux stagiaires

Il faut donc une pédagogie adaptée à ce contexte (ce sera l’objet d’un prochain article – notez qu’il risque d’y avoir des bouleversement pour Drupal 8 qui sera assez différent à enseigner). Il faut être capable d’expliquer les forces et faiblesses de Drupal, et l’intérêt de s’investir dedans. Mais il faut surtout être capable de transmettre, non pas un maximum d’informations, mais un maximum de savoir-faire !

C’est pareil dans tous les domaines. Dans le bâtiment, ce qui à de la valeur, ce n’est pas de montrer comment jeter du crépît sur un mûr et passer la taloche dessus. Ce qui à de la valeur, c’est le petit geste qu’on à mis des années à affiner et qui fait qu’on se fatigue moins, qu’on est plus précis, et au final, qu’on travaille 2X plus vite qu’un débutant. Ce n’est pas la proportion théorique de sable / ciment / eau qu’il faut pour faire du béton, mais le coup d’oeil dans la bétonnière pour savoir s’il est suffisamment gras ou pas.

Tous les développeurs savent lire et peuvent de débrouiller avec une documentation, ou un « Pro Drupal Developpment« . Le formateur doit être capable d’aller à l’essentiel, de faire le tri dans la masse d’informations pour ne retenir que les plus pertinentes. Un formateur doit donc proposer une plus-value réelle.

Pour cela, il n’y a pas 10 000 solutions : il doit s’adapter à ses stagiaires. Mes formations ne sont jamais les même, car j’élabore le programme en amont, mais aussi pendant la formation, pour coller au mieux au besoin réel. Avec des programmeurs expérimentés on va pouvoir aller dans sujets plus ardus que les API de base, ou bien, je leur tends des pièges ou leur proposes défis afin de toujours les maintenir en tension, et intéressés, de sorte qu’ils en retirent un maximum de choses (quelque soit leur niveau initial).

Une formation n’est pas un bourrage de crâne d’une liste, la plus longue possible, d’API à connaître par coeur. C’est tout l’inverse. Il s’agit d’expliquer comment Drupal est construit autour de concepts imbriqués les uns les autres et de leurs variantes. Comme ça, quand le développeur est face à une situation qu’il ne connaît pas, il sait s’orienter et trouver des solutions par lui même.

D’une certaine manière, on peut dire qu’une formation ne sert pas à savoir écrire du code, mais à le lire.

Compte rendu : Drink & Drupal Toulouse décembre 2013

Hier soir, j’ai fait une présentation de Drupal Commons 3.5 lors du Drink & Drupal à la cantine à Toulouse.

Je mettrais les slides en ligne bientôt.

DrinknDrupal1

Ambiance très sympa.

Nous en avons profité pour faire un petit test rapide de « talky.io« , une plateforme dont le code est en partie Open Source de webconférence basée sur WebRTC.

C’était assez fun de passer en webcam alors qu’on était tous dans la même pièce. Ceci dit, tout le monde a été d’accord sur l’intérêt d’intégrer cette technologie (ou une autre telle que Google Hangout – avec l’avantage que la session se retrouve archivée pour le public) lors des prochaines présentations, de sorte que d’autres puissent être de la partie, même s’ils sont loin ou indisponibles.

Nous en avons profité pour faire un point de fin d’année et voir comment organiser l’année qui arrive. Il a été retenu notamment de prévoir les conférences plus en amont, sur un calendrier glissant de 3 mois, et d’être plus présent sur drupalfr (notamment d’y poster nos présentations).