Billets avec le tag “développement”

Tests et gestion des dates/heures avec Ruby/Rails

Dans chaque application Internet de nombreux traitements sont dépendants de la date ou de l’heure :

  • affichage d’une offre promotionnelle durant une période donnée
  • documents visibles uniquement à partir de la date de publication
  • envoi de mailing seulement aux utilisateurs inscrits depuis le …
  • affichage d’un logo différent en fonction de la saison, du mois, de l’heure de la journée

Cette liste n’est pas exhaustive mais je suis sûr que vous avez également déjà rencontré cette situation. Il n’est pas difficile de gérer ces cas avec Ruby On Rails, une méthode spécifique (ou un named_scope) dans votre modèle avec les bonnes conditions et le tour est joué pour tout ce qui est relatif à la base de données. Un petit helper est suffisant pour afficher les différents logos en fonction de la date, de l’heure …

Mais quand est-il des tests ?

En effet, admettons que je veuille afficher un message de bienvenue différent en fonction de l’heure à mes visiteurs. Pour celà je vais utiliser un helper “message_bienvenue” que je placerai dans mon fichier application_helper.rb.

Mais commençons par écrire des tests unitaires que nous placerons dans le fichier application_helper_test.rb afin de vérifier que l’on obtienne bien ce que l’on souhaite :

def test_message_bienvenue_should_return_bonjour_if_hour_before_18
  assert_equal("Bonjour", message_bienvenue)
end
 
def test_message_bienvenue_should_return_bonsoir_if_hour_after_18
  assert_equal("Bonsoir", message_bienvenue)
end

Vous comprenez tout de suite que mes tests ne peuvent pas en l’état réussir tous les deux puisqu’à une heure donnée, soit le premier test réussira, soit le second ! Nous devons donc trouver un moyen de faire croire à Ruby que le test est exécuté à l’heure qui nous intéresse. Nous allons pour celà utiliser un helper qui a été élaboré au fil de cette discussion. Le fichier time_helper.rb est disponible ici et je vous conseille de le placer à la racine de votre dossier de test, au même niveau que le fichier test_helper.rb.

Grâce à cet helper que l’on inclus en ajoutant :

require File.dirname(__FILE__) + '/../time_helper'

au début du fichier de test, nous pouvons désormais améliorer nos tests grâce à la fonction “pretend_now_is” :

def test_message_bienvenue_should_return_bonjour_if_hour_before_18
  pretend_now_is(Time.local(2008, 12, 23, 14, 05)) do
    assert_equal("Bonjour", message_bienvenue)
  end
end
 
def test_message_bienvenue_should_return_bonsoir_if_hour_after_18
  pretend_now_is(Time.local(2008, 12, 23, 19, 23)) do
    assert_equal("Bonsoir", message_bienvenue)
  end
end

Grâce à cette fonction pretend_now_is, lorsque votre test est exécuté, la date et l’heure sont fixés à la date et l’heure que vous passez en paramètres. Nos tests ne passent toujours pas et c’est logique puisque nous n’avons pas écrit le helper message_bienvenue.

Nous allons donc écrire le code minimum pour faire passer nos tests :

def message_bienvenue
  if Time.now.hour < 18
    "Bonjour"
  else
    "Bonsoir"
  end
end

Cette fois les tests unitaires passent, nous avons donc atteint notre objectif !

Articles relatifs

Validation des adresses emails avec Rails, soyez prudent !

Rails n’intègre pas de validation standard pour les emails (puisqu’il est très difficile de répondre à toutes les exigences de vérification de la RFC 2822 et RFC 3696).

Petite surprise aujourd’hui, l’expression régulière archi-utilisée par tous les Railseurs (puisque publiée notamment sur la doc officielle) ne prends même pas en compte le fait qu’une virgule ne doit pas apparaître dans une adresse email !

A chaque problème sa solution, j’ai choisi la facilité en installant le plugin validates_email_format_of qui m’a permis de régler ce fâcheux problème en à peine 2 minutes puisque je n’ai eu qu’à remplacer validates_format_of par validates_email_format_of dans mon modèle.

Articles relatifs

Mettre le libellé des champs dans les champs avec Prototype

Lorsqu’un formulaire doit être réduit à son strict minimum il arrive parfois que l’on souhaite intégrer les libellés des champs directement dans ces derniers. Cette technique est généralement connue sous le nom de “watermarking”.

Plusieurs articles ont déjà traités de l’aspect validation/accessibilité de cette méthode comme par exemple ici ou ici. Je ne vais pas revenir sur ces aspects mais plutôt sur les solutions Javascript à notre disposition pour arriver à nos fins. D’un côté un plugin a été développé pour JQuery mais je n’avait pas trouvé d’équivalent pour Prototype (qui lui est intégré en standard dans Rails).

Après avoir tenté sans grande conviction de porter le plugin pour Prototype j’ai fini par trouver (bien caché !) un portage de la librairie sous Prototype sur cette page. Le code fonctionne très bien et implémente toutes les fonctionnalités d’origine de la librairie JQuery.

Après avoir appelé le fichier watermark.js il suffit d’une ligne pour ajouter un watermark sur un champs de formulaire :

$('id_de_mon_champs').Watermark('Nom');

Ainsi tous les traitements sont associés au champs et vous n’avez plus à vous en occuper ormis lors de l’envoi du formulaire ou vous devez retirer tous les watermarks de votre formulaire pour éviter d’avoir des données erronées.

Pour cela il suffit d’ajouter un observer sur votre formulaire et de faire un appel à Watermark.HideAll() avant de poster le formulaire :

$('id_de_mon_formulaire').observe('submit', function(event){
Watermark.Hideall();
})

Etant donné que l’ajout du watermark est géré en Javascript, vous pouvez sans problème initialiser votre formulaire avec des valeurs si nécessaire et votre formulaire restera complètement fonctionnel si jamais Javascript n’était pas activé.

Articles relatifs

Vérifier la qualité du code d’une application Ruby on Rails - Partie 4

Ce billet est issu de la traduction/adaptation de l’excellent billet de Matt Moore et a été repris avec son accord.

Tous les tests passent avant que le code soit mergé dans le dépôt.

Chacun peut garder sa copie de travail locale comme sauvegarde (git facilite cette approche). Mais dès qu’un produit est lancé, ne mergez jamais votre code avec la branche en cours d’utilisation tant que tous les tests ne passent pas.

Tous les problèmes corrigés sur un produit en production sont testés pour éviter les régressions.

La pire chose que vous pouvez faire dans votre business est d’avoir le même bug deux fois. Empêchez un problème de se reproduire grâce à des tests de régressions. Un utilisateur peut comprendre qu’un bug survienne une fois. Pas qu’il réapparaisse !

Le code des plugins installés est passé en revue (code review)

La plupart des plugins de la communauté Ruby on Rails sont généralement bien voir très bien écrits. Cependant, le nombre de plugins mal conçu va augmenter. Passez toujours en revue le code d’un plugin avant de l’utiliser en production. En général, plus le code est court, simple, testé et facile à comprendre, meilleur est le plugin !

Comprenez vous comment ça fonctionne ? Les impacts sur les performances ?

Articles relatifs

Vérifier la qualité du code d’une application Ruby on Rails - Partie 3

Ce billet est issu de la traduction/adaptation de l’excellent billet de Matt Moore et a été repris avec son accord.

La logique qui est dupliquée entre deux (ou plus) applications est transformée en plugin gemifié-

Maintenant que les plugins peuvent être gemifiés, il n’y a aucune raison de ne pas faire de plugins. Ils sont faciles à faire et désormais faciles à réutiliser et gérer entre les déploiements.

Contrairement à d’autres framework, les plugins dans Ruby On Rails sont très légers et faciles à coder. Il peut être intéressant de faire un plugin même si ce n’est que pour 5 ou 6 lignes de code.

Et plus généralement, votre code sera plus simple à migrer vers un autre framework Ruby comme Merb par exemple.

STI (Single Table Inheritance) n’est utilisée nulle part !

J’ai vu pas mal d’applications rails. Je n’ai jamais vu une application Rails ou l’utilisation de STI était une bonne décision. Je l’ai vu souvent lorsque quelqu’un est nouveau et pense que STI est une bonne manière de partager du code.

Mais avec Rails, il est tellement simple d’ajouter des colonnes à des tables et de partager du code entre des modèles … sans STI !

Il vaut mieux générer différents modèles et utiliser un module ou deux pour partager de la logique entre les deux. L’utilisation de partials communes permet également de partager le code des vues. Si vous utilisez STI, vous allez lier les deux modèles d’une manière dont il sera difficile de se défaire… une migration de données n’est jamais fun !

Les associations polymorphiques, en revanche, sont encouragées !

Chaque choix de design doit conduire au design le plus simple possible pour les besoins actuels. Ne faites pas d’hypothèses sur des futures fonctionnalités pour vos choix de design.

Ceci peut être résumé  tout simplement par : “The Rails Way”. Ce paradigme est aussi important pour les chefs de projets que pour les développeurs - ces deux types de personnes ont la responsabilité de s’assurer qu’il est bien suivi !

Le chapitre 4 de Getting Real l’explique très bien mais nous proposons ici un petit résumé. Si vous faites des suppositions au lieu de designer votre application selon les faits, inévitablement vos suppositions seront fausses.  Certaines seront peut être justes mais tous les designs et développements qui reposent sur des suppositions fausses rendent les choses plus complexes, plus difficiles à corriger et plus difficiles à améliorer.

Codez plutôt à partir des choses dont vous êtes sûrs, lancez rapidement une version, regardez les utilisateurs et itérez rapidement. C’est un des avantages majeurs des applications en lignes sur les applications clientes - utilisez le donc à son maximum !

Une couverture de tests quasi complète existe au plus haut niveau de l’application : sur et entre les actions des contrôleurs. La couverture est la plus complète pour le code le plus utilisé.

Même si les tests unitaires peuvent être importants pour le développement itératif, la plupart des applications Rails jeunes ont  un modèle assez simple. Vous devez faire attention que tous les points d’interactions pour les utilisateurs sont bien testés et restent fonctionnels release après release.

La méthode la plus simple pour choisir les priorités dans votre couverture de test ? Par le nombre d’utilisateurs finaux qui vont utiliser cette portion de code.

Articles relatifs

Quelques conseils pour le déploiement d’une application Rails

Capture-1

L’image choisie pour illustrer cet article est volontairement provocatrice et vous l’aurez sûrement reconnue (elle n’est pas de moi - voir crédit en fin de billet). J’ai choisie cette image car je pense que grâce à Rails et à quelques autres outils, le déploiement n’est absolument pas quelque chose de difficile et stressant comme certains tendent à le montrer avec des applications PHP par exemple.

1 - Utiliser un outil de gestion de versions

Que ce soit Subversion, CVS, Git ou n’importe quel autre outil de gestion de version, ne faites jamais l’impasse sur cet outil. La plupart de ces outils sont gratuits et open-source et si vous décidez de ne pas laisser votre dépôt (repository) en local, il ne vous coûtera que quelques euros par mois pour profiter d’un service hébergé (j’utilise assembla.com par exemple). Même si vous êtes l’unique développeur du projet, la gestion de version vous permettra de revenir sans problème à une version stable du projet.

Idéallement vous pouvez travailler avec deux branches différents, une pour les développements en cours et un pour les releases. Lorsque vous avez fini une modification et qu’elle est prête à être déployée, vous n’avez qu’à merger votre branche de développement dans la branche de release. Ceci vous permet de faire des gros développements qui durent longtemps tout en assurant la maintenance régulières du projet.

Enfin n’oubliez pas, ne jamais déposer des modifications si celles-ci ne passent pas tous les tests (voir également point 4) !

2 - Utiliser Capistrano

Capistrano est un outil destiné à l’automatisation de tâches via SSH. Il est très connu et utilisé dans la communauté Ruby et Ruby On Rails car il permet notamment d’automatiser les déploiements d’une application.

Il permet de gérer un déploiement d’une application sur plusieurs serveurs (mongrel, base de données…) depuis un outil de gestion de versions (comme Subversion). En une seule ligne de commande (cap deploy par exemple) vous pourrez ainsi déployer une nouvelle version de votre application sans aucun soucis ! Les fichiers sont extraits du dépôt, les migrations exécutées etc… Si jamais un déploiement venait à mal se passer (?), il vous suffit de lancer la commande cap rollback et votre application sera remise dans son état précédent !

Vous l’aurez compris, Capistrano est la pierre centrale d’un déploiement simple, sûr et serein !

3 - Utiliser un serveur de pré-production

Même si vous pensez que votre machine de développement reproduit fidèlement votre environnement de production, il est très difficile d’en être sûr à 100% tout le temps. Investissez donc dans un serveur de pré-production qui sera une copie exacte de votre serveur de production. Avant de déployer en production une nouvelle version, déployez là en pré-production pour vous assurer que tout fonctionne comme prévu.

Capistrano dispose d’une extension “multiple-stages” pour vous obliger à définir lors du déploiement vers quel environnement vous souhaitez déployer votre application.

4 - Tester, tester, tester

Rails intègre tous les outils nécessaires à la réalisation de tests unitaires, fonctionnels et d’intégrations. Profitez-en ! J’en reparlerai dans un prochain billet mais je ne peux que vous recommander de faire du développement piloté par les tests (Test-driven development), vous dormirez mieux là nuit ;-)

5 - Non, rien d’autre !

Pas besoins de 15 conseils, si vous appliquez correctement les 4 conseils ci-dessus, vous êtes à l’abri de la plupart des problèmes et surtout, vous pouvez revenir en quelques secondes dans un état stable !

Crédit image : logo de Capistrano

Articles relatifs

Vérifier la qualité du code d’une application Ruby on Rails - Partie 2

Ce billet est issu de la traduction/adaptation de l’excellent billet de Matt Moore et a été repris avec son accord.

Tous les appels à la méthode find avec des paramètres personnalisés qui sont fait à plus d’un endroit utilisent les named_scope plutôt qu’une méthode spécifique. 

Les named_scope doivent changer votre manière d’utiliser la méthode find. S’il ne vous semble pas évident que cette règle apparaisse ici, vous devez revoir vos bases et comprendre parfaitement la puissance des named_scope. Les named_scope chaînés sont la méthode la plus lisible d’effectuer des finds avec des conditions. Vous devez les utiliser.

NdT : excellente introduction en français aux named_scope et aux autres nouveautés de Rails 2.1 ici.

.find et .find_by_ ne sont jamais utilisés dans vos vues ou dans vos helpers.

Si vous utilisez .find ou .find_by_ sur un de vos modèles dans une vue, il y a 99% de chance qu’il y ait une meilleure manière de faire ça - et vous devez le faire !

Dans le pire des cas, vous devez utiliser un named_scope et l’appeler depuis la base du modèle. Le plus souvent, vous devez appeler une association ou une méthode personnalisée de votre modèle (sur laquelle vous pouvez chaîner un named_scope).

Par exemple, si vous voulez trouver tous les articles récents pour les lister  dans une vue d’un billet (@post) vous avez sûrement écrit : Articles.find(:all, :conditions =>…). Mais vous devriez plutôt écrire : Articles.recent (named_scope) ou encore mieux @post.related.recent (named_scope chaînés).

Il n’y a aucun code personnalisé qui duplique une fonctionnalité intégrée à Rails.

Même si c’est une règle générale de la programmation, elle est encore plus importante avec Rails. Contrairement à d’autres frameworks ou langages, Ruby on Rails fournis beaucoup de helpers pour afficher les choses correctement et pour faire des tâches courantes. Mais elles sont disséminées dans plein de fichiers différents - des modules qui sont mis ensemble au moment opportun.

Heureusement, le code de base de Rails est très bien écrit, même aux endroit ou il manque de la documentation. Pour trouver les méthodes que vous pouvez utiliser, je vous suggère de garder une copie du code source de Rails dans votre éditeur de texte ou votre IDE - dès que vous en avez besoin, vous pouvez faire une recherche dans les sources de Rails.

Le code a été écrit sans répétition (Don’t Repeat Yourself - Ne vous répétez pas) durant tout le développement.

Etant donnée la manière dont Ruby a été conçu, il est très simple de ne pas répéter son code durant le développement. Créez des helpers, créez des modules, créez des plugins. Tout le temps, tout le temps, tout le temps !

Toutes les fonctionnalités utilisées dans deux modèles ou plus ont été transformées en module ou en librairie.

Peut être que le plus gros avantage de Ruby sur les langages du style Java est les mixins (modules). Ne l’ignorez pas et utiliser les à bon escient.

En orientation objet à la manière Java, pour partager une fonctionnalité entre des classes, vous devez généralement écrire une sous-classe. En Ruby ce n’est pas le cas, vous pouvez mélanger des fonctionnalités de plusieurs modules différent dans n’importe quelle classe ou objet, même durant l’exécution.

Prenez le temps de bien comprendre les modules et utilisez les pour partager du code (qui était dupliqué) entre des modèles (et des contrôleurs). !

Articles relatifs

Suivi des erreurs de vos applications Rails avec Hoptoad

image

Par défaut, lorsque qu’une erreur de votre application survient (erreur 500), Rails se contente d’afficher la page 500.html située dans le répertoire Public. Il est donc de votre ressort de remonter l’erreur afin de pouvoir la corriger afin qu’elle ne se reproduise plus.

Hoptoad est un service en ligne gratuit qui vous propose de se charger de vous informer des erreurs de votre application. Pour celà vous devez vous inscrire puis intégrer Hoptoad dans votre application. Pour celà vous devez tout d’abord installer le plugin hoptoad_notifier :

script/plugin install git://github.com/thoughtbot/hoptoad_notifier.git

Puis créer un fichier hoptoad.rb dans votre dossier /config/initiliazers/ contenant le code suivvant :

HoptoadNotifier.configure do |config|
  config.api_key = 'votre_cle_ici'
end

Enfin pour finir, il ne vous reste plus qu’à ajouter la ligne suivante dans votre fichier app/controllers/application.rb :

include HoptoadNotifier::Catcher

Désormais toutes les erreurs remontées par votre application apparaîtrons dans l’interface de Hoptoad. Hoptoad vous informe à votre convenance de ces erreurs par courriel ou directement dans son interface web et fait également office de suivi de bogues simplifié pour les erreurs qui lui sont remontées. Hoptoad dispose d’une API qui doit permettre de le connecter à d’autres services comme un outil de suivi de projet mais je ne connais pas encore d’intégration existante avec un outil comme Lighthouse par exemple.

Articles relatifs

Vérifier la qualité du code d’une application Ruby on Rails - Partie 1

Ce billet et les trois prochains billets qui composent cette série sont issus de la traduction/adaptation de l’excellent billet de Matt Moore et ont été repris avec son accord.

Ruby On Rails est une des combinaisons langage/framework les plus difficiles à maitriser. Pour quelqu’un qui s’est formé avec C, C++ et Java, Ruby a une approche très différente (et meilleure !) de l’orientation objet et Rails est un framework qui repose beaucoup sur des bonnes pratiques à garder constamment à l’esprit.

Il est donc primordial que les développeurs qui se lancent dans ce couple Ruby/Ruby On Rails sortent du style Java pour produire un code qui respecte les bonnes pratiques de Ruby et de Ruby On Rails. Nous allons passer en revue les grands points qui font d’une application Ruby On Rails une application bien développée.

Chaque action d’un contrôleur contient un seul appel à une méthode du modèle autre qu’un appel à un Find ou à un Create initial. Faites des méthodes new et update personnalisées dans votre modèle avec tout le code nécessaire aux traitements.

Fat models and skinny controllers (gros modèles et contrôleurs épurés) est la méthodologie préconisée dans Rails. Dans presque tous les cas, vous pouvez placer toute la logique dans les modèles, ainsi les contrôleurs ressemblent comme deux gouttes d’eau aux contrôleurs générés par script/generate. Vous n’avez qu’à changer les appels aux méthodes génériques new et update_attributes par des méthodes personnalisées de votre modèle. Un exemple simple est le cas ou les attributs du modèles doivent être mis à jour par un utilisateur particulier :

@modele.update_attributes_by_user(params[:modele], current_user)

Le seul cas ou la logique doit être placée dans le contrôleur intervient si vous devez afficher une autre action ou effectuer une redirection spécifique.

Seules une ou deux variables d’instance sont partagées entre chaque contrôleur et la vue.

Il est très facile de partager beaucoup de variables d’instance entre les contrôleurs et les vues en Rails et ceci peu rapidement conduire à un code ingérable. Ceci est également potentiellement dangereux pour les performances puisque cela finira par faire double emploi avec des associations existantes. Vos contrôleurs doivent gérer uniquement une variable d’instance et  éventuellement une seconde pour le current_user. Ainsi, tous les appels vers des associations sont chargés “à la demande” et peuvent par exemple être mis en cache à un seul endroit.

Cette méthode fonctionne également très bien pour la mise en cache de fragments puisque vous pouvez vérifier le contenu du cache dans vos vues avant de charger les associations.

Par exemple, plutôt que de créer dans votre contrôleur Blog deux variables d’instance @post et @related_post, créer plutôt une seule variable @post et créez dans votre modèle Post une méthode related_posts afin de pouvoir appeler @post.related_posts dans vos vues. 

Tous les noms de modèles et de variables sont évidents (pour un nouveau développeur) et le plus court possible sans utiliser d’abréviations

Le nommage est difficile. Plus particulièrement pour les développeurs qui sont plongés dans une application : ce qui est évident pour vous qui avez le contexte de l’application bien en tête ne sera pas forcément évident plus tard ou pour un nouveau venu dans le projet.

Une des meilleures choses en Ruby et Ruby On Rails est justement que les noms sont cours et évidents. Ne détruisez pas cette immense force !

Si vous n’arrivez pas à trouver un nom ingénieux, clair et court immédiatement, finissez de coder votre méthode et mettez un TODO. En fin de journée, tentez de vous déconnecter complètement du contexte et renommez vos variables et méthodes.

Articles relatifs

Intégrer vos fichiers javascripts et CSS par vue ou partial dans Rails

Un code HTML valide nécessite d’intégrer les fichiers javascripts et CSS uniquement entre les balises <header> de vos pages. Il arrive pourtant fréquemment que l’on ai besoin d’un fichier CSS ou javascript propre à une vue ou à un partial. Dans ce cas nous serions tenter de simplement intégrer les fichiers javascripts et CSS dans ce fichier. Pourtant il existe des alternatives simples et efficaces afin de s’assurer que ces inclusions soient bien faites entre les balises <header> de votre page.

Vous pouvez par exemple utiliser les plugins Styler et Javascripters qui vous demande de renommer vos fichiers en fonction des nom d’actions ou de contrôleurs ou vous voulez qu’ils soient inclus. Celui-ci présente à mon avis des gros inconvénients puisque si vous souhaitez inclure 2 fichiers CSS spécifiques, vous êtes obligé de les concaténer dans un seul fichier ce qui n’est, vous en conviendrez, pas toujours très “DRY” (Don’t Repeat Yourself - Ne vous répétez pas).

Needy controllers est un autre plugin qui vous permet de spécifier les fichiers javascripts et CSS à inclure directement dans vos contrôleurs. Il gère les propriétés :only et :except pour vous permettre de gérer finement les inclusions. Bien que ce plugin soit très souple, il ne me convient pas puisqu’il lie très fortement les vues (les fichiers CSS et javascript) aux contrôleurs. Il ne respecte donc pas les principes de séparation des couches du modèle MVC.

La solution que j’ai retenu repose sur des méthodes standards de Rails : content_for et yeld. La méthode content_for permet de spécifier un bloc qui sera stocké pour être ensuite affiché par la méthode yeld. Vous comprenez aisément que ces méthodes peuvent être mises en oeuvre pour intégrer vos fichiers javascripts et CSS en respectant les principes DRY et MVC.

Pratiquement, insérons un appel à yeld entre les balises <head> de notre layout :

<head>
	<%= stylesheet_link_tag 'demo' %>
	<%= yield "page_header" %>
</head>

puis dans les vues ou vous avez besoin d’utiliser des fichiers CSS ou javascript spécifiques, il ne vous plus qu’à utiliser le code suivant :

<% content_for("page_header") do %>
	<%= stylesheet_link_tag 'monfichier.css' %>
	<%= javascript_include_tag 'monfichier.js' %>
<% end %>

Cette méthode est bien sûr réutilisable dans beaucoup d’autres situations !

Articles relatifs


Creative Commons License