• chevron_right

      Une UI responsive grâce à la règle de trois

      news.movim.eu / PutainDeCode · Thursday, 21 March, 2019 - 00:00 · 6 minutes

    Vous venez de coder un composant TwitterButton (avec React, Vue, en suivant une méthodo BEM, OOCSS, ou autre: c'est comme vous voulez) et franchement c'est du beau boulot: le rendu est vraiment très joli, kudos au designer.

    Seulement très vite, ce dernier jette un coup d'oeil à la recette et vous fait un petit retour parce qu'il :

    1. vous a fait parvenir des maquettes "mobile-first" et trouve le résultat "un peu petit sur son iMac 27 pouces"
    2. vous a fait parvenir des maquettes "desktop-first" et trouve le résultat "un peu gros sur son iPhone XS"

    Vous ajoutez donc quelques media queries pour adapter le style de ce bouton en fonction de la largeur du viewport. Ses dimensions changent maintenant lorsque la page fait plus de 768px de large, puis lorsqu'elle fait plus de 968px et enfin plus de 1200px . Un chouia fastidieux.

    Vous pestez un peu sur votre collègue qui aurait dû vous fournir toutes les maquettes (alors qu'il n'a pas forcément eu le temps de les créer) et lui peste car vous l'avez dérangé toutes les 2 minutes pour obtenir ces mesures intermédiaires.

    Il vous reste 72 composants à coder. Super ambiance dans les bureaux 👏🏼

    Plutôt que de demander à votre supérieur Jean-Michel de prendre parti pour résoudre ce problème, nous allons faire appel aux MATHS .

    L'interpolation linéaire entre 2 valeurs

    Des termes foutrement complexes pour définir quelque chose de très simple: il s'agit de faire transiter une valeur γ de α à β de façon linéaire et dans notre cas borné dans un intervalle donnée.

    Explication schématisée de l

    En partant de ça, nous allons définir une UI fluide à l'aide de 3 variables :

    • baseFontSize: number (px value)
    • scaleRatio: number (abs value)
    • fluidRange: [number (px value), number (px value)]

    Prenons l'exemple d'un site web où, en mobile-first, la taille de police par défaut ( baseFontSize ) est de 16px . On souhaiterait que celle-ci soit de 20px lorsque le viewport fait plus de 1600px de large (donc que le coefficient d'agrandissement - scaleRatio - soit de 20 / 16 = 1.25 ) et que la transition pour passer de 16 à 20 ne se déclenche pas avant que le viewport fasse au moins 480px de large.

    Exemple d

    La fonction suivante va nous permettre d'obtenir cette fameuse interpolation linéaire sous le forme d'une formule CSS avec calc() :

    // on utilise JS par praticitélet getLinearInterpolation = (  baseFontSize, // number  scaleRatio, // number  fluidRange // [number, number]) => {  let maxFontSize = baseFontSize * scaleRatio;  let [rangeStart, rangeEnd] = fluidRange;  let multiplier = (baseFontSize - maxFontSize) / (rangeStart - rangeEnd);  let fixed = maxFontSize - multiplier * rangeEnd;  return`calc(${fixed}px + ${100 * multiplier}vw)`;};

    Si vous copiez-collez ça comme un sagouin dans la console devtools de votre navigateur web et tentez un essai avec les valeurs de notre exemple, vous obtiendrez normalement :

    Le résultat de notre appel de fonction

    Voyons maintenant comment nous servir de ça.

    Un coefficient d'agrandissement global

    L'intérêt de cette valeur, c'est qu'elle va nous permettre de modifier toutes les dimensions que l'on veut de façon progressive et proportionnelle .

    Petit exemple, simple, basique :

    <html><body><h1class="title">Hello world</h1><divclass="red-block"></div></body></html>
    // exemple avec SCSShtml {  font-size: 16px; // baseFontSize}@media (min-width: 480px /* fluidRange start */) {  html {    // l'interpolation linéairefont-size: calc(14.285714285714285px + 0.35714285714285715vw);  }}@media (min-width: 1600px /* fluidRange end */) {  html {    font-size: 20px; // baseFontSize * scaleRatio  }}// par défaut dans les navigateurs 1rem = 16px, cette fonction nous simplifie les divisions// si vous faites du CSS-in-JS, let fluid = v => `${v / 16}rem` fait le job@function fluid($value) {  @return $value / 16 + rem;}.title {  // si largeur du viewport < 480px -> font-size = 24px// si largeur du viewport > 1600px -> font-size = 24 * 1.25 = 30px// si 480px < largeur du viewport < 1600px -> 24px < font-size < 30pxfont-size: fluid(24);}.red-block {  background-color: red;  // les dimensions seront contenues entre 100px et 100 * 1.25 = 125pxheight: fluid(100);  width: fluid(100);}
    résultat quand on joue sur la largeur du viewport(Cliquez sur le gif pour le voir en taille réelle)

    Forcer une font-size par défaut, c'est MAL

    (On va se mentir et tenter d'ignorer le fait que tout le monde utilise le zoom)

    En effet, l'utilisateur peut toujours choisir d'avoir une taille de police plus petite ou plus grande que celle par défaut ( 16px ) et c'est franchement pas très accessible de forcer.

    On va donc modifier notre fonction JS et tenir compte de ça.

    let getCSSFluidConfig = (  baseFontSize, // number  scaleRatio, // number  fluidRange // [number, number]) => {  let toRem = value => value / 16;  let maxFontSize = baseFontSize * scaleRatio;  let baseRemFontSize = toRem(baseFontSize);  let maxRemFontSize = toRem(maxFontSize);  let [rangeStart, rangeEnd] = fluidRange;  // on évite rem pour les media queries: merci Safari// pas de soucis pour utiliser toRem malgré tout:// les media queries sont à la racine du documentlet emRangeStart = toRem(rangeStart);  let emRangeEnd = toRem(rangeEnd);  let multiplier =    (baseRemFontSize - maxRemFontSize) / (emRangeStart - emRangeEnd);  let fixed = maxRemFontSize - multiplier * emRangeEnd;  // on en profite également pour retourner l'intégralité du CSS voulureturn`html { font-size: ${baseRemFontSize}rem }@media (min-width: ${emRangeStart}em) {  html { font-size: calc(${fixed}rem + ${100 * multiplier}vw) }}@media (min-width: ${emRangeEnd}em) {  html { font-size: ${maxRemFontSize}rem }}`;};

    Et voilà ! Ça continue de faire ce que l'on veut, mais en prenant en compte la taille de police par défaut définie par l'utilisateur.

    Un exemple un peu plus complexe

    Vous vous êtes empressé d'embêter le designer à nouveau afin de déterminer ces 3 variables ensemble: ça sera donc une font-size comprise entre 16px et 18px (donc une UI qui scale jusqu'à 18 / 16 = 1.125 …vous êtes encore frileux à l'idée) entre 480px et 1440px !

    Il est maintenant temps de modifier ce fameux bouton.

    getCSSFluidConfig(16, 1.125, [480, 1440]);/* -> "html { font-size: 1rem }@media (min-width: 30em) {  html { font-size: calc(0.9375rem + 0.20833333333333334vw) }}@media (min-width: 90em) {  html { font-size: 1.125rem }}" */
    // le code généréhtml {  font-size: 1rem;}@media (min-width: 30em) {  html {    font-size: calc(0.9375rem + 0.20833333333333334vw);  }}@media (min-width: 90em) {  html {    font-size: 1.125rem;  }}// fonctions utilitaires@function fluid($value) {  @return $value / 16 + rem;}// le reste du CSSbody {  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,    Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";}.twitter-btn {  align-items: center;  display: flex;  background-color: #1da1f3;  border: 1px solid #218de4; // il ne serait pas logique que border-width soit fluideborder-radius: 4px; // idem pour border-radiuspadding: fluid(4);  padding-right: fluid(8);  box-shadow: 05px5px -5px rgba(0, 0, 0, 0.25);}.twitter-btn svg {  height: fluid(24);  width: fluid(24);}.twitter-btnspan {  color: #fff;  font-size: fluid(14);  margin-left: fluid(4);}

    Ainsi,

    • la font-size par défaut fera entre 1rem et 1.125rem
      ( 16px et 18px si réglage navigateur par défaut)
    • le padding de .twitter-btn fera entre 0.25rem et 0.28125rem
      ( 4px et 4.5px )
    • la height et la width du svg feront entre 1.5rem et 1.6875rem
      ( 24px et 27px )
    • etc… vous avez l'idée, tout reste proportionnel.
    résultat quand on joue sur la largeur du viewport(Cliquez sur le gif pour le voir en taille réelle)

    La différence est très subtile (mais vous étiez frileux). L'avantage, c'est que si vous changez d'avis dans 3 semaines pour finalement passer sur un agrandissement de x1.5 à 2560px de large, il vous suffira générer un nouveau ce petit bout de code, de copier/coller les quelques lignes obtenues au début de votre fichier CSS …et c'est tout ! Inutile de revenir dans les composants ou de refaire un quelconque calcul.

    Pour que ce soit encore plus simple, je vous ai concocté un petit générateur :

    Il ne vous qu'à profiter de toute ces heures gagnées en invitant votre (maintenant pote) graphiste à boire une bière ! 🍻

    • wifi_tethering open_in_new

      This post is public

      putaindecode.io /articles/une-ui-responsive-grace-a-la-regle-de-trois

    • chevron_right

      Introduction à la méthodologie RUD

      news.movim.eu / PutainDeCode · Tuesday, 19 March, 2019 - 00:00 · 6 minutes

    DISCLAIMER : Je me suis rendu coupable de tous les crimes contre la lisibilité que je décris ici, de A à Z.Je ne prétends aucunement que faire ces choses fait de vous (ou moi du coup hein, on se protège) de mauvais devs, je dis simplement que peut-être qu'il est temps qu'en tant qu'industrie nous nous posions pour réfléchir sur ce que nous devons défendre. Je pense que le code peut être simple, je pense que connaître les comportements arcanes d'un langage peut être à la fois une force et une faiblesse. Je pense que le développement doit être accessible au plus grand nombre. Je pense qu'il est temps d'en finir avec la notion de vrai ou de faux développeur. Je vous souhaite une bonne lecture, les opinions exprimées ici sont les miennes donc n'hésitez pas à me coller un procès au cul, à moi et moi seul (je partage pas).

    Salut les copains, je profite de mon article annuel pour vous parler d'un autre truc qui commence doucement à m'éplucher les mirettes dans vos pratiques actuelles du développement informatique et pour cette fois, je connais un peu plus mon sujet.

    Voyez-vous, J'ACCUSE; J'accuse vous, j'accuse moi, j'accuse tout, j'accuse toi. Je vous accuse tous autant que vous êtes de bien trop vous prendre la tête sur le styling de vos pages. Vous vous faites royalement chier à trouver la ligne de code élégante pour régler votre problème sans avoir l'élémentaire courtoisie de vous demander si un manos précédent n'a pas réussi à régler un problème corollaire sinon adjacent via StackOverflow . Que ce soit avec Flex ou sans Flex, Grid ou sans Grid, float:left ou sans float:left , vous vous fourvoyez à la race .

    Soyez sans craintes très chers amis car joj (c'est moi, je m'appelle plus skinnyfoetusboy, surprise !) a la solution à tous vos petits maux, bobos et tracas. J'ai récemment élaboré une méthodologie CSS qui vous permettra de maintenir votre code plus efficacement, rendra la relecture plus simple et fera même revenir l'être aimé.

    La recette miracle tient en trois lettre : RUD .

    Rajoutez Une Div.

    Rajoutez. Une. Div.

    Le postulat de base est simple, il arrive régulièrement que nous cherchions la pureté dans notre code, cet instant où la grâce divine guide nos doigts pour écrire le code à notre place et où la frénésie remplace avantageusement le café dégueulasse à 35¢ de la machine d'à côté afin d'enfin venir à bout du centrage de cette div qui vous gonfle depuis bien trop longtemps, et puis merde quoi, c'est pas à ça que ça devait servir, Flex ?
    Vous tapotez ardemment sur votre clavier, Glenn Gould dans les oreilles comme sur les doigts pour trouver la solution à ce problème, putain, pourquoi quand ça marche sur IE ça foire sur Chrome et pourquoi quand ça marche sur Chrome ça foire sur IE ?

    rud.jpgMoi, avant d'avoir rajouté une div vs. Moi, après avoir rajouté une div. Effets garantis.

    Vous cherchez depuis trop longtemps comment régler ça efficacement, depuis tellement longtemps alors que la solution est bien plus simple : RAJOUTEZ. UNE. DIV.Enveloppez votre problème dans une div, foutez un justify-whatever: center et voilà.
    Posez-vous la question : pourquoi est-ce que vous n'avez pas rajouté cette div plus tôt ?Pris dans un orgueil mal-placé et dans la volonté de faire beau/élégant/malin/stylé/wow-je-vais-en-faire-un-codepen plutôt que de faire simplement bien et maintenable, et malgré la meilleure méthodologie BEM du monde, on s'évertue à rentrer du :before , du :after et d'autres tas de trucs qui pourraient être vachement mieux branlés en rajoutant simplement une div dans le DOM à l'endroit où elle devrait être : dans le template.
    Pourquoi vous créez des éléments dans votre CSS bordel ?

    Pourquoi j'en vois des qui gueulent sur le CSS-in-JS et qui font à côté la défense du HTML-in-CSS ?

    "Oui mais je vais quand même pas rajouter une div simplement pour afficher un chevron alors que je peux simplement claquer un :before ?" Si, si, vous allez faire ça, ça va vachement simplifier la peer-review de la pauvre personne qui s'en chargera, et ça aidera la personne qui relira votre code dans six mois (dans 90% des cas : vous) à comprendre ce que vous cherchiez à faire dans votre esprit malade.

    La pureté du code n'est qu'une pauvre manœuvre de gatekeeping pour vous prouver que, oui mon chéri, maman t'aime fort car tu es très malin, bravo, tu gères des ternaires de huit lignes dans ta tête je suis fière de toi.
    En faisant ce genre de choses vous ne faites que perpétuer les croyances selon lesquelles le développement est une pratique arcane réservée à une élite alors que vous êtes en train de développer le Wordpress de tonton Jean-Marc.

    L'autre bonne nouvelle vis-à-vis de cette méthodologie tout bonnement novatrice est qu'elle s'applique en réalité à tous vos besoins de développement, non pas en rajoutant des divs autour de vos conteneurs Docker (votre devops vous cassera la gueule si vous faites ça) mais en apprenant simplement à accepter qu'un code explicite est plus lisible, maintenable et propre qu'un code malin.
    Je parlais plus haut de ternaires de huit lignes (expérience véridique), et je vous pose la question : quand vous écrivez un truc pareil, à aucun moment vous ne vous dites "euh dis donc, je serais pas un peu en train de me compliquer la vie" ?

    Le développement informatique n'est pas un concours de minimalisme, vous n'êtes pas payés à l'absence de lignes de code, vos solutions alambiquées en 30 caractères ne sont que des proofs of concept face à la réalité de l'industrie.

    Combien j'en ai vu qui étaient capables de me sortir des RegExp de tête ou de claquer du bitwise à toutes les sauces et de les utiliser, parfois pertinemment ? Plein en fait, des gens très talentueux d'ailleurs.
    Mais, les features compliquées du langage ont un sens, une raison d'être, et elles sont là pour vous, pas contre vous. Ainsi, vouloir à tout prix, à tout moment, utiliser les fonctionnalités les plus poussées pour accomplir les besoins les plus triviaux c'est simplement du fayotage à base de "regarde, j'ai bien appris ma leçon" (et on aime pas les fayots, relisez Le Petit Nicolas).

    Je ne vous dis pas d'écrire du mauvais code (ni repris ni échangé ni remboursé je pars à Ibiza avec l'argent des abonnés) ni d'écrire le code le plus simple possible (parce que si vous faites ça ça redevient compliqué, faites pas votre app uniquement avec des if-statements, vous y êtes encore dans trente ans) :
    Comprenez simplement vos outils et sachez lesquels vous maîtrisez.

    Il sera peut-être parfois plus dur d'écrire du code ultra explicite mais croyez-moi bien quand je vous dis que vous serez content de pouvoir vous relire quand votre ternaire-dont-vous-êtes-super-fier-putain-j'ai-bossé pétera inévitablement au lieu d'être seul sur le sable, les yeux dans l'eau à essayer de vous remémorer votre mindset de l'époque en vous flagellant.

    Certains me diront peut-être "oui mais c'est une bonne pratique de faire X ou Y" et je vous le dis, du code en prod vaut cent fois mieux que du code dans le manuel des Castors Juniors du web, même si ce dernier est "hyper propre" ou " approuvé par Douglas Crockford ".

    Il n'y a de bonnes pratiques que celles qui vous permettent de travailler efficacement en équipe et avec vous-même .

    La vérité c'est que le développement web peut être simple et propre, et que le code spaghetti est toujours du code spaghetti même quand vous le comprenez (parce que vous êtes le seul à le comprendre) et qu'il vous fait vous sentir malin.Si vous tenez tant que ça à faire du code illisible, allez donc faire de l'assembleur ou du brainfuck.

    Je retourne me coucher.

    • wifi_tethering open_in_new

      This post is public

      putaindecode.io /articles/introduction-a-rud

    • chevron_right

      Comment on a fait ce site

      news.movim.eu / PutainDeCode · Monday, 18 March, 2019 - 00:00 · 5 minutes

    Puisqu'on vient de sortir une refonte du site, c'est l'occasion de faire un tour sur le processus qui nous y a amené.

    tl;dr;

    On prend des markdown et des fichiers Reason et on génère des HTML, des JS, des JSON mais pas de CSS

    Un nouveau site

    Avant ça, le site n'avait pas énormément évolué depuis quelques années. On a commencé à parler d'un redesign complet du site il y a un an et demi, on a maquetté la chose (c'est le design que vous voyez maintenant), mais on n'a rien foutu par manque de temps et par flemme de s'attaquer à un pareil chantier.

    On s'est quand même finalement décidé à retaper le site en un weekend, parce qu'on emmerde les proverbes sur les cordonniers.

    Alors comment on a fait ?

    Revoir les besoins

    Comme tout projet, on accumule au gré des années. On avait à l'époque un script JS qui parsait l'historique Git et tapait l'API GitHub pour fournir des données qui se sont avérées être trop granulaires pour nos besoins (et qui foirait une fois sur deux dès qu'une nouvelle personne voulait contribuer au projet).

    On ajoutait des petites features trop tôt, dès qu'une demande apparaissait dans les issues. Et ces features nous bloquaient pour en produire de nouvelles qui avaient plus d'intérêt pour la vie de l'organisation et du blog (notamment au vu des podcasts arrivés depuis 2016).

    En prenant un peu de recul, on a réalisé que nos besoin se résumaient à trois points importants :

    • une home
    • une zone articles
    • une zone podcasts

    Tout refaire sans déglinguer l'historique git

    Quand on s'est lancé dans l'ouvrage de refaire le site, il y avait un impératif : préserver les contributions de nos auteurs.

    D'un autre côté, partir d'un repository existant peut énormément limiter la création (alors que partir d'un projet tout frais tout neuf ça motive). On a du coup choisi une approche alternative: copier le projet, l'altérer à foison, et coller le résultat dans une énorme PR.

    Partir d'un package.json vierge était essentiel. On avait beaucoup trop de trucs.

    Les technos

    On a choisir de partir sur ReasonML , parce que c'est une technologie dans laquelle on croit, que dans l'équipe on est tous familiers avec React et parce qu'avec son type system , elle nous apporte des avantages non négligeables sur un projet pouvant être édité par un grand nombre de personnes: c'est une sorte de garde-fou.

    Pour le styling, si vous me suivez depuis longtemps, vous savez que j'adore CSS , je suis donc parti sur bs-css , un DSL statiquement typé qui utilise emotion , ce qui nous permet d'envoyer au client uniquement les styles requis .

    L'approche technique: une static SPA

    La question qu'on s'est posée : quel est le moyen le plus efficace de livrer une page de blog aux lecteurs ?

    Et la réponse qui s'est imposée à nous était dans la veine de ce qu'on avait déjà fait par le passé : une SPA statique .

    Qu'est-ce qu'une SPA statique ? C'est un site statique conçu comme une single page application . On conçoit le site comme une application React côté client, et on va pré-rendre les pages non pas côté serveur, mais dans notre système d'intégration continue.

    Pourquoi de l'hébergement statique ? Parce que c'est moins cher (voire gratuit), qu'on est principalement front et que la dernière fois que je me suis connecté à la console AWS j'y suis resté coincé pendant 5 jours.

    Ce que ça apporte : un chargement initial extrêmement rapide , une navigation optimale et des besoins en serveur réduits au minimum .

    Quand un lecteur arrive sur le site, il récupère une version de la page déjà rendue au moment du build, le client ne fait que "hydrater" la page. Lors que le lecteur navigue vers une autre page, le client va uniquement chercher la donnée dont il a besoin pour la page de destination.

    En développement local, chaque page démarre avec un data-store vide , et les composants vont demander le chargement des données . En production, chaque page est livrée rendue , avec le data-store contenant les informations dont elle a besoin , toute navigation ultérieure sera comme en mode local: les composants vont demander le chargement de ce qui leur manque.

    Ce mode de fonctionnement requiert une certaine discipline concernant les endroits où la donnée peut être stockée. Dans notre cas, on a choisi de la placer dans l'état du composant qui orchestre l'application, et de le faire sous la forme suivante:

    type state = {  articles: Map.String.t(RequestStatus.t(Result.t(Post.t, Errors.t))),  articleList: RequestStatus.t(Result.t(array(PostShallow.t), Errors.t)),  podcasts: Map.String.t(RequestStatus.t(Result.t(Podcast.t, Errors.t))),  podcastList: RequestStatus.t(Result.t(array(PodcastShallow.t), Errors.t)),  home: RequestStatus.t(Result.t(Home.t, Errors.t)),};

    Cet état peut stocker l'intégralité des données du blog , comme il peut stocker le minimum possible . Si vous voulez en savoir plus, n'hésitez pas à naviguer dans les sources du site.

    Une approche alternative est de stocker la donnée requise par chaque URL, mais cette approche s'avère moins efficace au niveau du cache: si on a déjà toutes les données depuis une autre URL, on va quand même devoir les charger à nouveau.

    Coder le blog

    Le blog était organisé d'une manière … chaotique. L'emplacement des fichiers markdown dans le repository définissait leur URL sur le site (on devait se dire que c'était une bonne idée à l'époque). Pour plus de perennité, on a choisi de passer à un système où le nom ou l'emplacement du fichier n'avaient pas d'impact sur l'endroit où se retrouve sur le site. Ça nous permet de les organiser par date, par sujet ou par contrib dans le futur sans pour autant influer sur les URLs.

    Avec jojmaht , on a pris la tâche ingrate de bouger et transformer la centaine d'articles existants, avec leurs médias, vers une organisation à plat , plus simple à gérer.

    Une fois cette tâche gérée, on n'avait plus qu'à récupérer les posts et à les générer aux URLs qui vont bien.

    Gérer la retro-compatibilité

    On a profité de ce chantier pour réécrire les URLs des articles vers des formats plus lisibles (e.g. /articles/js/react -> /articles/introduction-a-react ).

    Pour preserver les anciennes URLs, on a indiqué l'ancienne URL des articles dans chaque fichier markdown, et on a généré à ces endroits là une page HTML:

    <!DOCTYPE html><metahttp-equiv="refresh"content="0;URL=NOUVELLE_URL" />

    On se sert également de cette ancienne URL comme identifiant de page pour notre système de commentaires qui tourne avec disqus parce que j'ai pas trouvé la page pour migrer les URLs sur leur admin.

    Si vous voulez en savoir un peu plus, n'hésitez pas à parcourir la source du projet . Et n'hésitez pas à contribuer au blog si l'envie vous vient.

    Bisous.

    • wifi_tethering open_in_new

      This post is public

      putaindecode.io /articles/comment-on-a-fait-ce-site