K33G_ORG's Blog

home @k33g_org rss all posts

Blog Posts (last 5)

27 Mar 2014

comments »

M33KI ? Kézako ?

La 1ère fois où j'ai trouvé que Java était intéressant pour faire du Web (remettons les choses à leur place, je faisais de l'ASP.Net) c'est en découvrant Play!> Framework 1. Pouvoir faire des apps web autonomes (j'utilisais IIS que je trouvais beaucoup plus sympa que Websphere), comprendre réellement le MVC (mon équipe faisait du STRUTS, et comment dire ...), l'Auto-reload !!!, ... J'ai même commis un tuto géant avec mon camarade @loic_d : PlayRules. Bref, un nouveau monde s'offrait à moi :)

... jusqu'à l'arrivée de Play 2 qui mit à genoux mon petit macbook air :(

Je décidais donc de parfaire mon éducation Java par d'autres moyens, je m'amusais donc avec SparkJava : voir l'article N3rd.stack:[java] : faites votre propre stack java pour le web ... une sacrée usine, mais qui me valu l'insigne honneur d'être cité par les cast-codeurs (ok, je fais un peu cire-pompes comme ça, mais j'étais vraiment très fier). Lorsqu'un jour au bistro, @hgomez me parla d'un petit jeune prometteur qui développait son propre langage : Golo, et que ça allait envoyer du lourd (le petit jeune c'est @jponge). Je me dépêchais alors de contacter @jponge pour devenir Golo Testeur.

Quasiment dès le départ, j'ai essayé de voir comment je pouvais tordre la bête et l'utiliser pour faire des applis web, et après moult essais instructifs (et productifs), ce fut la naissance de M33ki.

Bon alors, c'est quoi !?

M33ki est un "micro-web-framework" en Golo avec comme base toujours mon framework fétiche SparkJava destiné à faire des services REST (mais pas que) et des applications web légères qui peuvent même tourner sur un RaspberryPI, un ChromeBook "crooté", ... tout en proposant des services intéressants (MongoDb, Redis, SSE, CORS, WebSocket, Promises, Actors (ok il faut le dire vite ;)) ... M33ki c'est aussi un formidable terrain de jeu, ainsi qu'un "gros" use case pour démontrer que l'on peut probablement tout faire avec Golo.

Mes inspirations ont été clairement : Play 1, mais aussi Node & Express, Ratpack et d'autres qui sont venus se greffer au fur et à mesure.

Et ça "marche" comment ?

Alors je vous passe l'installation (https://github.com/TypeUnsafe/m33ki#install-m33ki).

Créer un projet M33KI

Dans un terminal, tapez la commande m33ki et validez :

   _____  ________ ________  __   .__
  /     \ \_____  \\_____  \|  | _|__|
 /  \ /  \  _(__  <  _(__  <|  |/ /  |
/    Y    \/       \/       \    <|  |
\____|__  /______  /______  /__|_ \__|
        \/       \/       \/     \/
  WebApp server Golo powered (c) @k33g_org

OS : mac os x
Application name?>

Saisissez le nom de votre application (poney) et choisissez le type de projet (1- Golo Skeleton project) :

Application name?>poney
Creating poney application
1- copy /m33ki/jars to /Users/k33g_org/poney
2- copy /m33ki/libs to /Users/k33g_org/poney

reading configuration file
What kind of application ?
1- Golo Skeleton project
2- Hybrid project (Java + Golo)
number?>1

Remarque : le projet 2 "Hybrid" signifie bien que vous pouvez mixer le code Java et le code Golo, M33ki se débrouillera pour compiler la partie java automatiquement.

Maintenant vous pouvez aller dans le répertoire poney et lancer votre webapp avec la commande ./go.sh (ou go.bat si vous êtes sous windows) mais attendez un petit peu.

main.golo

Avant de lancer quoique ce soit, ouvrez le fichier poney/main.golo :

module main

import m33ki.spark
import m33ki.hot # requisite for "hot reloading"

import routes

function main = |args| {

  initialize(): static("/public"): port(8888)

  listenForChange("")

  loadRoutes()

}

Explications

  • listenForChange("") signifie qu'à chaque fois que vous ferez une modification, votre projet sera re-démarré, M33ki écoute à la racine de la Webapp
  • static("/public")signifie que vos "assets" html, js, ... sont dans le répertoire public
  • loadRoutes() charge les routes définies dans app/routes/routes.golo

Routes

Toujours dans main.golo, supprimez loadRoutes(), et nous allons écrire nos 1ères routes dans le fichier principal :

Ajouter l'import suivant import m33ki.jackson en en-tête de fichier, puis définissez les 2 routes suivantes :

  GET("/hello", |request, response| {
    response: type("application/json")
    return Json(): toJsonString(map[["hello", "world"]])
  })

  GET("/hello/:name", |request, response| {
    response: type("application/json")
    let name = request: params(":name")
    return Json(): toJsonString(map[["hello", name]])
  })

Démarrez :

cd poney
./go.sh

Maintenant,

c'est simple comme bonjour, vous pouvez bien sûr faire des POST, PUT, DELETE (cf. https://github.com/TypeUnsafe/m33ki#rest-example), mais aussi chaîner les closures lors de la requête, ce qui peut être très pratique par exemple pour gérer l'authentification. Essayez ceci (sans arrêter votre Webapp, je vous rappelle que ça redémarre tout seul) :

  GET("/try"
    , |request, response| { # check authentication
        let session = request: session(true)
        if session: attribute("authenticated") is null {
          return [false, "<h1>Don't even think about this!</h1>"]
        }
      }
    , |request, response| {
        return "<h1>Victory</h1>"
      }
  )

  GET("/login", |request, response| {
    let session = request: session(true)
    session: attribute("authenticated", true)
    return "<h1>Welcome</h1>"
  })

Conclusion

C'était une rapide présentation de la "bébête". Vous voyez Golo permet d'aller assez loin, mais on peut faire beaucoup d'autres choses comme ceci :

Jouer avec Redis :

  let bob = humans
    : model(): setId("bob"): setName("Bob Morane")
    : save()

Jouer avec MongoDb :

  humans: model(): setName("Bob Morane"): setAge(38): insert()

  humans: query(
    Qb("age"): lessThan(39): get()
  ): each(|human| -> println("- " + human))

Faire du calcul parallèle : (là c'est encore les balbutiements)

  let actor1 = Actor(executor): delay(500_L)
    : onReceive(|num, self| {
        num: times(|index|-> println("actor1 : " + index))
    })
    : start()

  let actor2 = Actor(executor): delay(300_L)
    : onReceive(|num, self| {
        num: times(|index|-> println("actor2 : " + index))
    })
    : start()

  actor1: tell(15): stop()
  actor2: tell(5): tell(v5) : stop()

Ou même :

  let hope = Hope(executor)
    : todo(|iterations| { # = 500
      let computation = compute()
      return computation
    })
    : done(|computation| {
      println(computation)
    })
    : go(500)

Je le répète, c'est de l'expérimentation (pour partie), et si vous passez par DevoxxFr cette année, je vais expliquer comment j'ai pu coder ce genre de choses (et c'est simple) (et reproductible avec d'autres langages de la JVM comme Groovy) : Golo, de la sucrette syntaxique pour vos applications Java.

Last but not least

Il existe un projet "sister" de M33ki : Hi qui est un générateur de code "à la Yeoman" mais en Golo, et qui sait utiliser Bower et Npm. Comme Yeoman, il utilise un système de plugins et dispose notamment en standard d'un plugin dédié à M33ki : hi.gen.m33kig qui permet de générer les routes CRUD Golo, les modèles MongoDb et une partie du front js/html avec Backbone et React, que je n'ai pas encore documenté si ce n'est par ici https://gist.github.com/k33g/9245205 (draft mode).

allez, j'arrête ;)


comments »


22 Mar 2014

comments »

J'apprends Scala avec Finatra: Part I

Je suis obligé de reconnaître que je "trolle" sur Scala sans réellement en faire. Mais à chaque fois que j'ai essayé dans faire, je trouvais ça un peu obscur. Il y a peu @loic_d, connaissant mon intérêt pour les micro-frameworks m'a poussé ce lien http://finatra.info/. Finatra est un micro-framework web en Scala réalisé chez Twitter. En lisant le code d'exemple sur la home page j'ai trouvé ça tout de suite très lisible.

class HelloWorld extends Controller {
  
  get("/hello/:name") { request =>
    val name = request.routeParams.getOrElse("name", "default user")
    render.plain("hello " + name).toFuture
  }
}

Tiens, on peut faire du code Scala pas ésotérique !?. En allant faire un tour ici Scala School (toujours chez Twitter, tiens tiens!), cela semble se confirmer.

Du coup (et vu que de grosses boutiques s'y collent), je me suis dit "redonnons une chance à Scala" ... ou plutôt, je me redonne une chance de comprendre ;).

Je vais donc juste faire un petit rappel sur la manière de faire son premier projet Scala et sa première classe et ensuite nous passerons directement à la réalisation d'une application web avec Finatra avec un mini service json (mais mini mini).

Nous verrons aussi que nous pouvons facilement mettre en œuvre une fonctionnalité de rechargement et compilation automatique de l'application lorsque nous modifions le code.

Remarque: avez vous vu dans le code le mot clé toFuture ? Finatra est un framework web asynchrone.

Avertissement

Alors, attention, moi aussi j'apprends Scala (et Finatra), donc je peux dire des choses choquantes (ou peut-être fausses). Ce blog est propulsé par GitHub par ici : https://github.com/k33g/k33g.github.com, ce qui veut dire que vous pouvez faire des pull requests sur ce que j'écris pour m'aider à m'améliorer (merci d'avance), vous pouvez même déclarer des issues, mais je préfère les PR (comme ça vous bossez pour moi ;) ). Par contre il vous faudra un compte GitHub (et c'est l'occasion de le faire tout de suite si vous n'en avez pas).

Pré-requis

Remarque: sbt pour Scala Build Tools est un utilitaire destiner à vous faciliter la vie pour vos projets Scala.

Rappel : Classes & Objets

Avant de rentrer dans le dur, nous allons juste un peu "désacraliser" Scala et apprendre à faire une petite classe, pour bien vérifier que finalement, c'est simple.

Création du projet

Tout d'abord, nous allons créer une rapide structure de projet Scala, compréhensible par sbt, ce qui nous permettra de compiler notre code facilement.

Créez l'arborescence suivante (adaptez selon vos besoins) : (là on le fait à la main mais il existe des outils rassurez vous)

 demo
 |--src
    |--main
       |--scala
          |--org
             |--k33g
                |--models

Référence(s) pour aller plus loin sur la notion de création de projet

Programme principal

Dans demo/src/main/scala/org/k33g/ créez le fichier Demo.scala (remarquez que le nom Demo versus le nom du répertoire demo, ce n'est pas obligatoire, mais c'est plus propre) avec le code suivant :

package org.k33g

object Demo extends App {
  println("Hello World!")

}

Sauvegardez, ouvrez votre terminal ou votre console, allez dans demo (cd demo) et tapez sbt run (et validez). Ça va mouliner un peu (Scala n'est pas super green au démarrage), pour finir par vous afficher un splendide :

Hello World!

\o/

First Class : Human

Dans demo/src/main/scala/org/k33g/models créez le fichier Human.scala avec le code suivant :

package org.k33g.models

class Human(val firstName: String, val lastName: String) {

  def sayHello(): String = {
    return "Hello " + firstName + " " + lastName
  }
}

Nous venons juste de créer une classe Human avec 2 "propriétés" firstName et lastName et une méthode sayHello qui retourne une chaîne de caractères. Ce n'est pas trop violent, et vous remarquez que la définition des attributs de la classe par passage de paramètre au constructeur est assez élégante (je ne peux pas troller sur Scala constamment).

Modifiez ensuite le précédent fichier Demo.scala :

package org.k33g

import org.k33g.models._

object Demo extends App {

  var bob = new Human("Bob", "Morane")
  println(bob.sayHello())

}

Toujours dans demo lancez à nouveau un sbt run, vous allez obtenir :

Hello Bob Morane

Voilà, vous savez tout ;), Scala c'est facile ... On peut maintenant aller faire une application web en Scala (avec Finatra).

Ma première application Finatra

Installer Finatra

Chez moi (sous OSX), cela ressemble à ça :

FINATRA_HOME=/Users/k33g_org/finatra-1.5.2
export FINATRA_HOME
export PATH=$PATH:$FINATRA_HOME

Générez votre 1er projet

  • Tapez ceci : finatra new org.k33g.DemoWeb
  • A la question Install Bower components? (y/n) répondez y (cela va permettre par défaut de télécharger Bootstrap et jQuery)

Vous obtenez donc votre squelette de projet dans le répertoire DemoWeb. Mais avant de lancez quoique ce soit procédons à quelques réglages.

Préparez votre "stack front" avec Bower : un peu de javascript

Allez dans DemoWeb et modifiez bower.json en lui ajoutant 2 dépendances : backbone et underscore, de cette manière :

{
  "name": "DemoWeb",
  "version": "0.0.1",
  "license": "MIT",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "bootstrap" : "twbs/bootstrap",
    "backbone" : null,
    "underscore" : null
  }
}

Ensuite, lancez bower update (dans DemoWeb) et les frameworks javascript Backbone et Underscore seront téléchargés.

Modifiez (préparez) la page d'accueil

Modifiez src/main/resources/public/index.html de cette façon :

<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="icon" type="image/x-icon" href="/favicon.ico" />
    <title>Demo</title>
    <link rel="stylesheet" type="text/css" href="/components/bootstrap/dist/css/bootstrap.css">
  </head>
  <body>
    <div class="container">
      <header>
        <h1>Je me la joue en Scala</h1>
      </header>

    </div>
    <script src="/components/jquery/dist/jquery.js"></script>
    <script src="/components/underscore/underscore.js"></script>
    <script src="/components/backbone/backbone.js"></script>
    
  </body>
</html>

Modifiez le code de démarrage de l'application

Ouvrez src/main/scala/org/k33G/DemoWeb/App.scala et simplifiez le code de cette manière :

package org.k33g.DemoWeb

import com.twitter.finatra._
import com.twitter.finatra.ContentType._

object App extends FinatraServer {

  class MyApp extends Controller {

    get("/") { request =>
      render.static("index.html").toFuture
    }

  }

  register(new MyApp())
}

Nous nous contentons donc de dire qu'il faut afficher index.html si l'on appelle la racine du site / dans le navigateur.

Il est temps de tester

Il suffit de lancer la commande sbt run. La console sbt "va compiler" votre application et ensuite vous notifier que vous pouvez vous connecter : finatra: http server started on port: :7070, ouvrez donc http://localhost:7070/. Tout roule ? On passe donc à la suite. Arrêtez l'application : Ctrl + c.

Création d'un service json

Nous allons juste créer une classe Human (encore!) et nous la "publierons" au format json pour le navigateur.

Création de la classe Human

Tout d'abord créez un répertoire models dans le répertoire src/main/scala/org/k33g. Dans ce répertoire, créez une classe Human.scala avec le code source suivant :

package org.k33g.models

class Human(val id: String, val firstName: String, val lastName: String) {

}

Création de notre service

Ouvrez à nouveau src/main/scala/org/k33g/DemoWeb/App.scala, nous allons rajouter une "routes" qui fournira du jso, au navigateur :

Premièrement, pensez à importer les modèles : import org.k33g.models._ et ajoutez ceci :

get("/humans/:id") { request =>
  val id = request.routeParams.getOrElse("id", null)
  val bob = new Human(id, "Bob", "Morane")

  render.json(Map(
    "id" -> bob.id, 
    "firstName" -> bob.firstName, 
    "lastName" -> bob.lastName
  )).toFuture
}

Au final, vous aurez :

package org.k33g.DemoWeb

import com.twitter.finatra._
import com.twitter.finatra.ContentType._
import org.k33g.models._

object App extends FinatraServer {

  class MyApp extends Controller {

    get("/") { request =>
      render.static("index.html").toFuture
    }

    get("/humans/:id") { request =>
      val id = request.routeParams.getOrElse("id", null)
      val bob = new Human(id, "Bob", "Morane")

      render.json(Map(
        "id" -> bob.id, 
        "firstName" -> bob.firstName, 
        "lastName" -> bob.lastName
      )).toFuture
    }

  }

  register(new MyApp())
}

Testez en lançant sbt run et appelez http://localhost:7070/humans/42 et vous obtiendrez dans votre navigateur :

{"id":"42","firstName":"Bob","lastName":"Morane"}

Vous pouvez changer l'id dans l'url pour tester

Pas trop dur?

Remarque:

Pour les faignasses, sachez que vous pouvez remplacer :

render.json(Map(
  "id" -> bob.id, 
  "firstName" -> bob.firstName, 
  "lastName" -> bob.lastName
)).toFuture

par :

render.json(bob).toFuture

Utilisation du service json avec Backbone

Parce qu'une application web sans javascript n'est pas une vraie application web, retournez ouvrir index.html et ajouter le code suivant en vas de page juste avant la fermeture de la balise <body> (donc </body>) :

<script>

  var HumanModel = Backbone.Model.extend({
      urlRoot : "humans"
  });      

  $(function() {
    var bob = new HumanModel({id:"42"})
    bob.fetch()
      .done(function(){
        $("h1").html(bob.get("firstName") + " " + bob.get("lastName"));
      })
  });

</script>

Rafraîchissez votre page, vous allez voir que votre titre se met à jour avec les données du service json.

Auto-Reload

Ce qui me plaisez énormément dans Play!>1 (et 2), c'était le rechargement automatique (+compilation) lorsque l'on modifiait le code. Sachez que moyennant une petite "bidouille" ceci est très possible. Il suffit d'ajouter un plugin à sbt. Ce plugin est sbt-revolver.

Commencez par quitter la console sbt (Ctrl + c). Ensuite dans le répertoire project de votre application, créez un fichier plugins.sbt avec le contenu suivant :

addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2")

puis à la racine de votre projet, dans le fichier build.sbt ajoutez la ligne Revolver.settings comme ceci :

name := "DemoWeb"

version := "0.0.1-SNAPSHOT"

scalaVersion := "2.10.3"

libraryDependencies ++= Seq(
  "com.twitter" %% "finatra" % "1.5.2"
)

Revolver.settings

resolvers +=
  "Twitter" at "http://maven.twttr.com"

Relancez mais avec la commande duivante sbt ~re-start (qui va charger les dépendances nécessaires puis lancer votre application).

Maintenant à chaque fois que vous modifierez le code, sbt recompilera et relancera l'application.

Essayez ça par exemple : dans App.scala

get("/humans") { request =>
  val bob = new Human("42", "Bob", "Morane")
  val john = new Human("00", "John", "Doe")

  render.json(Array(bob, john)).toFuture
}

Sauvegardez, regardez votre console qui compile automatiquement, puis appelez http://localhost:7070/humans et vous obtenez :

[{"id":"42","firstName":"Bob","lastName":"Morane"},{"id":"00","firstName":"John","lastName":"Doe"}]

Magique!

Vous avez donc tout ce qu'il faut pour tester un peu tout ça et la prochaine fois on fait la suite des services avec un peu de base de données.

Enjoy! (et bon WE pluvieux)

Et encore merci @loic_d, j'ai fini par m'y mettre. ;)


comments »


28 Feb 2014

comments »

Backbone Patterns & Best Practices

J'ai eu la possibilité et la chance d'être relecteur du livre "Backbone.js Patterns &nd Best Practices" de Swarnendu De pour PACKT Publishing.

Tout d'abord, avant de vous parler du livre, je tenais à préciser (et je ne suis pas payé pour le dire) que j'aime beaucoup cette boutique d'édition, à la fois pour les sujets qu'elle propose (vous pouvez trouver des livres traitant de sujets que vous aurez du mal à trouver ailleurs ie: Meteor, Titanium, ...), les différents formats de livres : par exemple "Backbone.js Patterns &nd Best Practices" fait moins de 140 pages, du coup il va à l'essentiel, il est facile à lire (et plus abordable financièrement que de gros pavés que vous ne lirez jamais en entier, j'en ai plein mon placard ;)), etc. ... Et j'ai la nette impression que PACKT Publishing permet à pas mal d'auteurs en herbe de s'exprimer, et privilégie les expériences personnelles. Le process de "review" est efficace (et cadencé!), et en plus les remarques des relecteurs sont prises en comptes (pas toutes, mais nous ne sommes pas obligés de tous avoir le même avis).

Alt "3576OS_Backbone Practices.jpg"

Cette relecture de "Backbone.js Patterns &nd Best Practices" a été une expérience intéressante. L'auteur ne fait pas une reformulation de la documentation de Backbone, et on sent vraiment que c'est du vécu. Pendant le processus de relecture, j'ai pu retomber sur des problématiques que j'ai pu avoir (on se sent moins seul) mais j'ai appris quelques techniques sympathiques. J'ai tout particulièrement apprécié le passage sur les mixins, et je trouve enfin un auteur qui commence par parler du modèle objet de Backbone. Les chapitres sont courts et compréhensibles. Les exemples fonctionnent (et eux aussi sont compréhensibles), chaque composant de Backbone est abordé et peut donner l'occasion de parler de frameworks ou outils connexes comme Marionnette dans le chapitre sur les vues, le plugin Backbone.Validation dans le chapitre sur les modèles, ... Et les 2 derniers chapitres, de courtes introductions, vous mettent le pied à l'étrier pour structurer et déployer vos applications Backbone et faire du test.

Pour conclure, si vous faites déjà du Backbone, ce petit bouquin est un très bon complément pour vous perfectionner et vous donner des idées.

Bon allez j'attaque une revue sur un livre sur Grunt maintenant.


comments »


A voir : Les GROS tutos Play!> 1 & 2 !, Backbone