Skip to content

Blogs de Développeurs: Aggrégateur de Blogs d'Informatique sur .NET, Java, PHP, Ruby, Agile, Gestion de Projet

Forum Logiciel

Forum Logiciel : diffusion de connaissance et d’informations sur toutes les activités liées au développement d’applications informatiques en entreprise.

Blog Xebia France - J2EE, Agilité et SOA
Syndiquer le contenu Blog Xebia - Cabinet de conseil IT
Cabinet de conseil Agile spécialisé dans les technologies Big Data, DevOps, Web, Architectures Java et mobile
Mis à jour : il y a 6 heures 41 min

Les KProperty2 ou la réflexion signée Kotlin

mar, 09/19/2017 - 16:40

En parcourant la bibliothèque standard de Kotlin, section réflexion, on peut tomber sur des types tels que KProperty0, KProperty1 et KProperty2.

On comprend assez rapidement que les types KProperty* sont des types qui reprĂ©sentent et permettent de manipuler, par rĂ©flexion, des propriĂ©tĂ©s i.e. des variables dĂ©clarĂ©es dans un package ou dans une classe. On comprend, en revanche, un peu plus difficilement pourquoi des propriĂ©tĂ©s peuvent ĂŞtre reprĂ©sentĂ©es par plusieurs types (et surtout par trois types diffĂ©rents). En Java, par exemple, l’Ă©quivalent d’une propriĂ©tĂ© – un champ – est toujours reprĂ©sentĂ© par le type Field, qu’il soit statique ou non.

Cet article vous propose de dĂ©couvrir ce que les diffĂ©rents types KProperty* reprĂ©sentent. Nous commencerons donc par Ă©tudier les types KProperty0 et KProperty1 qui se rĂ©vèlent, au final, assez simples. Nous pourrons ensuite mieux aborder le type KProperty2, la configuration un peu inhabituelle qu’il reprĂ©sente et surtout en quoi il peut bien nous ĂŞtre utile.

Le type KProperty0

Comme le montre le code ci-dessous (lien gist), le type KProperty0 reprĂ©sente une variable immuable dĂ©clarĂ©e au niveau d’un package (sans aucun contexte).

package com.github.sergiords.kproperties

import kotlin.reflect.KProperty0

val name: String = "Bob"

fun main(args: Array<String>) {

    val kProperty0: KProperty0<String> = ::name

    val value: String = kProperty0() // value of the property "name"

    println(value) // prints "Bob"

}

Dans cet exemple, pour obtenir une instance du type KProperty0 reprĂ©sentant la variable immuable name on utilise l’opĂ©rateur « :: » (ligne 9) appliquĂ© Ă  la variable elle-mĂŞme. On voit que le type KProperty0 est paramĂ©trĂ© par le type de la propriĂ©té qu’il reprĂ©sente (String). L’instance kProperty0 peut ensuite ĂŞtre utilisĂ©e pour rĂ©cupĂ©rer la valeur de la variable (ligne 11).

Le type KProperty1

Le code ci-dessous (lien gist) met quant Ă  lui en Ă©vidence le type KProperty1 qui reprĂ©sente une variable immuable dĂ©clarĂ©e au niveau d’une classe (dans le contexte d’un type User).

package com.github.sergiords.kproperties

import kotlin.reflect.KProperty1

class User {

    val name: String = "Bob"

}

fun main(args: Array<String>) {

    val kProperty1: KProperty1<User, String> = User::name

    val user: User = User()

    val value: String = kProperty1(user) // value of the property "name" inside "user" instance

    println(value) // prints "Bob"

}

Pour obtenir une instance du type KProperty1 reprĂ©sentant la variable immuable name dans une instance du type User on utilise l’opĂ©rateur « :: » appliquĂ© au type User (ligne 13). On voit que le type KProperty1 est paramĂ©trĂ© par le type contenant la variable (User) et par le type de la propriĂ©té qu’il reprĂ©sente (String). L’instance kProperty1 peut ensuite ĂŞtre utilisĂ©e pour rĂ©cupĂ©rer la valeur de la variable immuable dans une instance du type User (ligne 17).

Le type KProperty2

Nous venons de voir les types KProperty0 et KProperty1, ils reprĂ©sentent respectivement une variable immuable dĂ©clarĂ©e au niveau d’un package (zĂ©ro contexte) et au niveau d’un type donnĂ© (un seul contexte, l’instance). Pour le type KProperty2 on suit le mĂŞme raisonnement en ajoutant un contexte. Le type KProperty2 reprĂ©sente donc une variable immuable dĂ©clarĂ©e dans deux contextes. Comment est-ce possible ? Avec les extensions de propriĂ©tĂ©s, mises en Ă©vidence ci-dessous (lien gist).

package com.github.sergiords.kproperties

import kotlin.reflect.KProperty2
import kotlin.reflect.full.declaredMemberExtensionProperties

class Magic {

    val String.magicLength: Int   // add property magicLength to String type inside Magic class only
        get() = this.length * 42

    fun length(arg: String): Int = arg.magicLength

}

fun main(args: Array<String>) {

    @Suppress("UNCHECKED_CAST")
    val kProperty2: KProperty2<Magic, String, Int> = Magic::class.declaredMemberExtensionProperties.single() as KProperty2<Magic, String, Int>

    val magic = Magic()

    val abcdValue: Int = kProperty2(magic, "ABCD") // value of the property "magicLength" inside "ABCD" and "magic" instances
    println(abcdValue) // since "ABCD".length = 4, prints 4 * 42 = 168

    val abcdeValue: Int = magic.length("ABCDE") // value of the property "magicLength" inside "ABCDE" and "magic" instances
    println(abcdeValue) // since "ABCDE".length = 5, prints 5 * 42 = 210

}

La syntaxe un peu particulière des lignes 8 et 9 permet de rattacher une variable immuable magicLength, au type String, uniquement accessible dans une instance du type Magic. Le this de la ligne 9 reprĂ©sente bien l’instance du type String qui reçoit cette nouvelle variable immuable. Cette syntaxe est une extension de propriĂ©tĂ© un peu particulière car elle est dĂ©clarĂ©e dans le contexte d’un autre type et c’est cette configuration de variable immuable que reprĂ©sente le type KProperty2.

Pour obtenir une instance du type KProperty2, on doit cette fois s’appuyer sur les extensions de propriĂ©tĂ©s dĂ©clarĂ©es au niveau du type Magic (ligne 18). On voit bien que le type KProperty2 est paramĂ©trĂ© par le type dans lequel il est dĂ©clarĂ© (Magic), par le type qui reçoit l’extension de propriĂ©tĂ© (String) et par le type de la propriĂ©tĂ© qu’il reprĂ©sente (Int). L’instance de kProperty2 peut ensuite ĂŞtre utilisĂ©e pour obtenir la valeur de la variable immuable magicLength d’une chaĂ®ne « ABCD » dans une instance donnĂ©e du type Magic (ligne 22).

Une utilisation plus standard de ces propriétés est la fonction Magic::length qui utilise cette extension de propriété, mais cette fois, directement dans le type Magic (déclaration à la ligne 11 et appel à la ligne 25).

Conclusion

L’objectif de cet article Ă©tait avant tout de comprendre ce que les diffĂ©rents types KProperty* pouvaient bien reprĂ©senter comme configuration. Si les types KProperty0 et KProperty1 reprĂ©sentent une configuration assez classique, il n’en est rien pour le type KProperty2.

La question qui nous vient alors naturellement Ă  l’esprit est la suivante : « mais Ă  quoi cela peut-il bien servir ? ». On peut voir le type KProperty2 comme la possibilitĂ© de reprĂ©senter des propriĂ©tĂ©s qui ne sont valables que lorsque deux contextes sont rĂ©unis. On peut, par exemple, reprĂ©senter la position d’une forme dans un conteneur avec le code ci-dessous (lien gist).

package com.github.sergiords.kproperties

class Form(val x: Int, val y: Int)

class Container(val x: Int, val y: Int) {

    val Form.xInContainer: Int
        get() = this.x - this@Container.x

    val Form.yInContainer: Int
        get() = this.y - this@Container.y

}

Dans l’exemple ci-dessus, une forme peut ainsi avoir une position absolue (Form.x, Form.y) et une position relative dĂ©finie dans un conteneur (Form.xInContainer, Form.yInContainer). Cette dernière position bien que rattachĂ©e au type Form, n’est dĂ©finie que dans le contexte du type Container. En dehors de ce contexte elle n’a pas de sens et n’est d’ailleurs pas accessible.

Catégories: Blog Société

Tester du code Spark – 2 – La pratique

mar, 09/19/2017 - 10:38

Que de la thĂ©orie. Les tests du code Spark semblent abonnĂ©s Ă  cette rĂ©alitĂ© : tout reste thĂ©orique. Ă€ croire qu’en rĂ©aliser est impossible. Il est grand temps de remĂ©dier Ă  ce problème et dĂ©montrer que le sujet est abordable par tous.

Quitter la thĂ©orie, c’est dĂ©buter par les bonnes pratiques. Des rĂ©flexes sur la spĂ©cification des jeux de tests jusqu’aux extensions des DSL Scala et Python qui simplifient les assertions autour des DataFrames en passant par l’utilisation de Spark-Testing-Base, cet article couvre le minimum nĂ©cessaire Ă  l’Ă©criture des tests en Spark.

AmĂ©liorer la lisibilitĂ© du contexte d’exĂ©cution du test

Dans un cas idĂ©al, un test contient trois sections : « Given », « When », et « Then ». Le « Given » dĂ©fini clairement le contexte d’exĂ©cution du test qui le rend spĂ©cifique. C’est ce contexte, appliquĂ© Ă  notre mĂ©thode testĂ©e (le « When ») qui provoque la sortie attendue (le « Then »). Il est important de chercher Ă  rĂ©duire la quantitĂ© d’informations prĂ©sentes dans ce contexte d’exĂ©cution dans l’objectif d’amĂ©liorer sa lisibilitĂ©.

Premièrement, oĂą doivent se situer les donnĂ©es de test ? Doivent-elles ĂŞtre externalisĂ©es dans un fichier dĂ©diĂ© ? Ou bien doivent-elles ĂŞtre insĂ©rĂ©es directement dans le code du test ? Mon prĂ©cĂ©dent article prĂ©conise de les intĂ©grer dans le code du test, Ă  l’exception des tests de validation d’un modèle de Machine Learning. Ă€ première vue, la solution du fichier permet de fournir un jeu de test plus consĂ©quent. Cependant, augmenter la taille du jeu de test en entrĂ©e entraĂ®ne de la difficultĂ© en termes de maintien de la cohĂ©sion entre le test et ses donnĂ©es.

Deuxièmement, comment initialiser un DataFrame contenant potentiellement beaucoup de colonnes ? La solution est en fait plutôt simple.

En Scala, la mĂ©canique de « case class » associĂ©e Ă  la mĂ©thode implicite d’une session Spark permet de conserver un maximum de simplicitĂ© comme le montre l’exemple suivant.

import org.apache.spark.sql.DataFrame
import org.scalatest.{FlatSpec, GivenWhenThen}

case class TestRow(column1: String = "", column2: String = "")

class SimpleSpec extends FlatSpec with GivenWhenThen with SparkSessionProvider {
  import sparkSession.implicit._
  
  "A Unit test" should "have a readable Given" in {
    Given("A specific value on column 1")
    val inputDataFrame: DataFrame = List(
      TestRow(column1 = "specific value")
    ).toDF()
    
    ???
  }
  
}

En Python, le « kwargs » fourni quelque chose de semblable Ă  la version Scala. Bien que plus lĂ©gère Ă  première vue, cette version convient principalement Ă  des cas simples de valeurs prĂ©cises. Toute inclusion d’une valeur nulle (None) impose d’initialiser et de fournir un schĂ©ma SparkSql (une instance de StructType).

import unittest2

spark_context = SparkContext()
spark_session = SparkSession(spark_context).builder.master("local[*]").appName("Unit tests").getOrCreate()
 
class TestSimple(unittest2.TestCase):
 
  def test_shoud_have_readable_give(self):
    # Given
    input_data_frame = spark_session.createDataFrame([
      Row(column1 = "specific value")
    ])
    ....

La comprĂ©hension du test est simple, en Python comme en Scala : le DataFrame d’entrĂ©e contient une ligne dont la particularitĂ© porte sur la colonne « column1 ».

Spark-Testing-Base, de nombreuses fonctionnalités pour différents langages

Une des bibliothèques les plus connues autour du test de programmes Spark est sans conteste Spark-Testing-Base. Cette bibliothèque propose de nombreuses fonctionnalitĂ©s pour diffĂ©rents langages (Scala, Java, Python) parmi lesquelles des classes d’aide Ă  la rĂ©daction d’assertions sur les RDD, DataFrames et DataSets et de tests basĂ©s sur l’utilisation d’un Mini-Cluster. Elle propose Ă©galement du support autour de ScalaCheck.

Une configuration simple

En Scala comme en Python, la procédure de configuration est simple.

En Scala, elle est dĂ©crite directement dans le readme du dĂ©pĂ´t Github du projet. De base, un ajout de dĂ©pendance Maven ou SBT et le tour est jouĂ© (il est toutefois recommandĂ© de correctement dimensionner la mĂ©moire car l’utilisation d’un contexte Spark local est assez gourmand). Attention Ă  bien prĂ©ciser la version voulue de Spark dans la dĂ©pendance.

val sparkVersion = "2.2.0"
val sparkTestingBaseVersion = "0.7.4"
libraryDependencies += "com.holdenkarau" %% "spark-testing-base" % s"${sparkVersion}_$sparkTestingBaseVersion" % "test"
    <dependency>
        <groupId>com.holdenkarau</groupId>
        <artifactId>spark-testing-base_${scala.version}</artifactId>
        <version>${spark.version}_${sparktestingbase.version}</version>
        <scope>test</scope>
    </dependency>

En Python, le package est disponible sur le dépôt PyPi comme tout autre package. Il est donc installable via PIP par la commande pip install spark-testing-base. Il suffit ensuite de placer la dépendance dans le fichier setup.py dans la zone tests_requires :

from setuptools import setup
 
setup(
  ...
  tests_requires=['spark-testing-base']
  ...
)

Cette bibliothèque propose trop de contenu pour qu’il soit totalement couvert dans cet article. Probablement sa fonctionnalitĂ© la plus utile, la classe DataFrameSuiteBase fourni le nĂ©cessaire Ă  un test simple dans Spark, en particulier des fonctions utilitaires pour la comparaison de DataFrames. Voici comment les utiliser :

class SimpleSpec extends FlatSpec with DataFrameSuiteBase {
  "Simple Spec" should "show how to use DataFrameSuiteBase" in {
    // Given
    val df = List(
      Balance(income=3, outcome=2)
    ).toDF()
 
    // When
    val result = df.filter(positiveAmount(_))
 
    // Then
    assertDataFrameEquals(df, result)
  }
 
  it should "also show to to deal with errors" in {
    // Given
    val df = List(
      Balance(income=2, outcome=3)
    ).toDF()


    // When
    val result = df.filter(positiveAmount(_))


    // Then
    intercept[TestFailedException]
      assertDataFrameEquals(df, result)
  }
}

Une fonctionnalité semblable est disponible dans la version Python de la bibliothèque. Il faut utiliser la classe SQLTestCase. Voici comment faire :

from pyspark.sql import Row
from sparktestingbase.sqltestcase import SQLTestCase
import unittest2

class SimpleTest(SQLTestCase):
  def test_do_nothing(self):
    rdd = self.sc.parallelize([Row(
        column1="foo"
    )])
    df = rdd.toDF()
    
    self.assertDataFrameEqual(df, df)
À utiliser pour des besoins spécifiques

Il est indĂ©niable qu’un framework tel que Spark-Testing-Base rend le code plus lisible. La quantitĂ© de mĂ©thode type « helpers » apporte une facilitĂ© d’Ă©criture des tests. Sur un petit projet, la simplicitĂ© de mise en Ĺ“uvre est flagrante.

Son utilisation apporte nĂ©anmoins quelques complexitĂ©s un peu cachĂ©es au premier abord. L’utilisation de cette bibliothèque par Maven/SBT provoque souvent le tĂ©lĂ©chargement d’une quantitĂ© astronomique de dĂ©pendances afin d’avoir Spark-Testing-Base Ă  disposition. Il arrive d’ailleurs parfois d’avoir des conflits de dĂ©pendances apportĂ©s par les dĂ©pendances transitives de Spark-Testing-Base, mais rien d’insoluble. Dans de nombreux cas, le besoin se situe au niveau d’une ou deux classes assez simples de cette bibliothèque. Beaucoup d’Ă©lĂ©ments seront Ă  ramener pour finalement quelques lignes de code. PrĂ©conisation personnelles : rĂ©Ă©crire le petit morceau de code Ă©quivalent de cette bibliothèque pour rĂ©pondre Ă  son besoin.

Enfin, un dernier point nĂ©gatif de ce framework est qu’il est moins fourni en Python, de quoi satisfaire principalement les utilisateurs de Spark en Scala.

En définitive, ce framework est à utiliser pour des besoins spécifiques. Certaines classes utilitaires sont assez complexes (telles que celles relatives à ScalaCheck) et il ne serait pas judicieux de les réécrire.

Simplifier l’Ă©criture des tests Spark en Scala

Lors de l’Ă©criture des tests Spark en Scala, il est classique d’utiliser les matchers de ScalaTest pour valider les attendus. Ceci fonctionne très bien pour valider des Ă©lĂ©ments tels que le contenu des schĂ©mas (les champs sont une collection de StructTypes que l’on peut valider) ou le contenu des DataFrames. Il s’agit d’une collection de Row. Puisque dans les tests, la quantitĂ© de donnĂ©e est limitĂ©e, la mĂ©thode collect est utilisable. Il est alors possible de tout ramener sur le driver pour utiliser les collections de base de Scala, donc les matchers de base, sans exploser la consommation mĂ©moire.

Voici un exemple type de test de schéma et de contenu de DataFrame :

class SimpleSparkAndScalaTest extends FlatSpec with Matchers with SparkSessionProvider {
  import sparkSession.implicit._

  def onlyPositiveBalance(inputDataFrame: DataFrame): DataFrame = {
    def positiveBalance(input: Row): Boolean = {
      input.getInt(input.fieldIndex("income")) - input.getInt(input.fieldIndex("outcome")) > 0
    }
    inputDataFrame.filter(positiveBalance(_))
  }
  
  case class Balance(id: Int, income: Int = 0, outcome: Int = 0)
  
  "Simple test" should "do something" in {
    // Given
    val inputDF = List(
      Balance(id = 1, income = 3, outcome = 2),
      Balance(id = 2, income = 3, outcome = 4)
    ).toDF()
    
    // When
    val result = onlyPositiveBalance(inputDF)
    
    // Then
    result.schema.map(_.name) should contain allOf ("income", "outcome")
    result.count() shouldBe 1
    result.map(row => row.getInt(row.fieldIndex("id"))).head shouldBe 1
  }

}

La couverture de test est Ă  un bon niveau puisque tout le code peut ainsi ĂŞtre testĂ©. Mais Ă  la lecture, il y a quelque chose de très dĂ©rangeant. La dernière ligne est trop complexe et est donc difficile Ă  lire. Il est grand temps de simplifier l’Ă©criture des tests en Scala.

Pour répondre à ce besoin, quelques lignes de code suffisent à créer un peudo DSL qui simplifie la lecture des tests. Par exemple, pour que les deux lignes de code suivantes soient équivalentes :

result.map(row => row.getString(row.fieldIndex("column_to_test"))).head shouldBe "correct_value"
field("column_to_test") of result.head() shouldBe "correct_value"

Les quelques lignes suivantes permettent cette syntaxe :

def field(name: String) = FieldMatcherOfRow(name)

case class FieldMatcherOfRow(fieldName: String) {
  def of(row: Row) = row.get(row.fieldIndex(fieldName))
}

Ainsi, la lecture se fait de façon proche du langage naturel : « Le champ « column_to_test » de la première ligne de mon DataFrame doit ĂŞtre « correct_value » ». Il faut ensuite laisser libre court Ă  son imagination pour crĂ©er d’autres contenus de ce type afin de rendre lisible tous les tests !

Simplifier l’Ă©criture des tests Spark en Python

Afin de simplifier Ă©galement l’Ă©criture de ces mĂŞmes tests Spark en Python, le manque de DSL est encore plus flagrant. En gĂ©nĂ©ral le framework PyHamcrest propose, selon mes critères (très subjectifs donc), la syntaxe la plus lisible et comprĂ©hensible. Ă€ l’instar de la version Scala, il est possible de crĂ©er des DSL qui rendent nos tests lisibles en Python. L’un des Ă©lĂ©ments importants Ă  tester sur un DataFrame est sa taille. La matcher PyHamcrest correspondant s’Ă©crit de la manière suivante :

class DataFrameCountMatcher(BaseMatcher):

    def __init__(self, expected_count):
        assert isinstance(expected_count, int), 'Provided count is not an int but %s' % type(expected_count)
        self.expected_count = expected_count

    def _matches(self, item):
        if not isinstance(item, DataFrame):
            return False
        return item.count() == self.expected_count

    def describe_to(self, description):
        description.append_text('Given DataFrame has count %d' % self.expected_count)

    def describe_mismatch(self, item, mismatch_description):
        if isinstance(item, DataFrame):
            mismatch_description.append_text('has count %d' % item.count())
        else:
            mismatch_description.append_text('%s is not a DataFrame' % type(item))


def has_count(expected_count):
    return DataFrameCountMatcher(expected_count)

Ce matcher est ensuite très facilement utilisable et produit une syntaxe claire :

class TestDataFrameCountMatcher(unittest.TestCase):

    def setUp(self):
        self.df = sql_context.createDataFrame([
            Row(key='value'),
            Row(key='value2')
        ])

    def test_has_the_right_count(self):
        assert_that(self.df, has_count(2))
Les tests sont l’affaire de tous

La prochaine fois qu’un collègue vous donnera une fausse bonne excuse pour ne pas Ă©crire ses tests en Spark, rappelez-lui que les tests sont l’affaire de tous et qu’il est possible d’Ă©crire des tests simples, maintenables et indĂ©pendants en utilisant ce framework.

Maintenant, même nos amis Data Scientists pourront écrire leurs tests unitaires !

Le prochain et dernier article de cette série traitera des tests de Spark en utilisant le Property Based Testing.

PROCHAIN ARTICLE, bientĂ´t

Tester du code Spark avec du Property Based Testing

Catégories: Blog Société

Revue de Presse Xebia

jeu, 09/14/2017 - 15:10

Revue de Presse Xebia
La revue de presse hebdomadaire des écosystèmes Java/JEE proposée par Xebia

Craftsmanship Java: Free at last http://blog.xebia.fr/author/dortegahttp://twitter.com/dicaormuhttp://github.com/dicaormuPar Diana Ortega

Mike Milinkovich directeur exĂ©cutive de la fondation Eclipse a Ă©crit dans son blog « Java: Free At Last », oĂą il analyse une partie des annonces faites dĂ©but septembre par Mark Reinold et Donald Smith d’ Oracle.

Les annonces parlent de l’implĂ©mentation de releases pĂ©riodiques du jdk, mais Milinkovich se focalise sur le dĂ©tail que java deviendrait finalement « free ».

Aujourd’hui les binaires java sont distribuĂ©s sous la licence « Oracle Binary Code License », mais Oracle a l’intention de les mettre directement avec l’OpenJDK sous licence GPL.

Pour plus d’information vous pouvez voir l’article de Micke Milinkovich.

 

 

Back Server-Sent Events

Dans sa version 5, Spring nous propose une alternative aux web-sockets pour notifier le front des changements coté server : les Server-Sent Events (ou SSE).

Cet article nous présente que sont les SSE et nous explique comment les mettre en place dans votre application Spring.

Node.js 8.5 http://www.gravatar.com/avatar/1e0ca9963bcd96ba434e5e4ffd972c2fhttp://blog.xebia.fr/author/%40aletaxin1http://twitter.com/ModuloMhttps://github.com/ModuloMPar Antoine Le Taxin

Une nouvelle release de Node.js vient de sortir !
Principaux ajouts Ă  cette version :

  • La prise en charge native des imports de modules ESM grâce au tag –experimental-modules.
  • L’implĂ©mentation d’une Performance Timing API.
  • La possibilitĂ© d’avoir accès, via la stack, aux traces des Ă©vènements async. 
  • Une mĂ©thode qui permet de directement de copier des fichiers grâce au module fs.

Pour le détail, voir le change log complet, ou une revue par Rising Stack des principales features avec des exemples.

 

Catégories: Blog Société

Zeenea : exploitez enfin vos Data Lakes !

jeu, 09/14/2017 - 10:45

header zeenea

logo zeeneaPour devenir une organisation “data-driven”, vos collaborateurs ont besoin d’un accès simple et rapide à des données organisées, de bonne qualité et sécurisées.

Afin d’accompagner cette Ă©volution, et forts d’expĂ©riences rĂ©ussies chez nos clients ces 7 dernières annĂ©es dans des missions Big Data, nous avons dĂ©veloppĂ© une solution autour de l’exploitation de Data Lakes. Cette solution a aujourd’hui pris son indĂ©pendance pour devenir Zeenea 

Catégories: Blog Société

EMR : Instancier son cluster Hadoop simplement

lun, 09/11/2017 - 16:45

Logo Amazon EMR

Amazon Elastic MapReduce (EMR) est le service qui simplifie la création et la mise à disposition d’une stack Hadoop complète et ajustable. Grâce à ce service, il suffit de quelques opérations pour créer un cluster Hadoop dans le Cloud embarquant les principaux outils de l’écosystème tels que YARN, Spark, Zeppelin, Hive, Presto, HBase et HDFS. Cet article propose de faire un tour d’horizon de ce service et de quelques moyens d’en profiter. Il s’inscrit dans une série d’articles autour de l’instanciation de clusters dans le Cloud.

Nous prĂ©senterons les raisons qui peuvent pousser Ă  utiliser EMR, puis nous parlerons brièvement des diffĂ©rents services Amazon impliquĂ©s. Ensuite, après avoir dĂ©terminĂ© l’architecture cible, nous passerons en revue les questions qu’il est indispensable de se poser, puis nous crĂ©erons notre cluster.

Pourquoi utiliser EMR ?

Il est intéressant d’utiliser EMR pour limiter le coût de l’infrastructure nécessaire à l’exécution des services Hadoop. Dans la plupart des cas, l’infrastructure englobant l’écosystème Hadoop n’est utile que durant la phase de processing de la donnée. Une fois le traitement terminé, l’infrastructure peut être détruite.

Voici la chaîne d’opérations à réaliser dans le cadre de traitements de type batch.

  1. Stocker les données dans le Cloud.
  2. Instancier un cluster Hadoop.
  3. Traiter les données au sein du cluster.
  4. Produire de nouvelles données ayant de la valeur.
  5. Stocker les données utiles résultantes dans le Cloud.
  6. DĂ©truire le cluster.
  7. Exploiter les résultats.

La solution EMR est flexible en terme d’infrastructure, de distribution Hadoop, de produits logiciels inclus et de durée de vie du cluster. De plus, le monitoring du cluster est inclus avec CloudWatch. Pour finir, EMR offre une interaction avec l’ensemble des autres services AWS.

L’utilisation d’EMR n’est pas restreinte Ă  des chaĂ®nes d’utilisation de type batch. EMR est capable de consommer un nombre important de ressources variĂ©es, ce qui ouvre la porte Ă  de nombreux usages.

Pré-requis AWS

EMR fait intervenir un ensemble de services AWS qu’il est bon d’introduire.

Amazon Virtual Private Cloud (VPC)

Tous les noeuds EMR s’exécutent dans un VPC au sein d’un sous réseau d’une zone de disponibilité (AZ). Pour rappel, en fonction d’une zone géographique où le service AWS est disponible comme par exemple en Europe (Dublin et bientôt Paris), il existe deux à trois zones de disponibilité (AZ). Pour y voir plus clair sur les VPC et avoir une vision complète, rien de tel que l’article de mon collègue Jeremy Pinsolle.

Identity and Access Management (IAM)

C’est le service qui permet la gestion des identitĂ©s et des accès. Ce service pourrait faire l’objet d’un article Ă  lui tout seul ! Pour rester sur notre sujet EMR, nous allons retenir que pour instancier le cluster EMR via API REST, il est nĂ©cessaire d’activer une clĂ© d’API dans IAM pour notre compte utilisateur AWS.

IAM permet d’attacher des stratégies de sécurité (policies) relatives à l’utilisation des services. Chaque stratégie est identifiable via un nom unique Amazon Resource Name (ARN) et peut être associée à des utilisateurs ou à des rôles. Ce système d’ARN est utilisé partout sur AWS, où tout est considéré comme une ressource.

Voici un exemple de stratégie permettant à l’utilisateur de changer son propre mot de passe dans IAM :

arn:aws:iam::aws:policy/IAMUserChangePassword

Au sein d’ IAM, des droits sont associĂ©s Ă  cette stratĂ©gie. Dans le cas prĂ©sent, si j’associe cette stratĂ©gie Ă  mon compte utilisateur et que j’ajoute des droits de lecture/Ă©criture, je pourrai Ă©crire ou lire sur le service IAM pour changer mon mot de passe.

Pour EMR, nous allons devoir créer deux rôles dans IAM.

Un premier rôle pour le service EMR : Celui-ci permettra à EMR de créer un subnet, et d’instancier des machines avec EC2.

arn:aws:iam::XXXXX:role/EMR_DefaultRole

Un second rôle pour les instances qui composent le cluster EMR pour qu’elles puissent par exemple récupérer des données sur S3 et consommer des services tiers.

arn:aws:iam::XXXXX:role/EMR_EC2_DefaultRole
EC2

Ce sont les instances de machines qui composent le cluster Hadoop. Il convient de choisir les types d’instances EC2 adĂ©quates au regard du nombre de composants dĂ©ployĂ©s et des performances attendues. Amazon fournit la liste des instances compatibles avec EMR. A titre d’exemple, une m3.xlarge avec ses 4vCPU, 15Go de RAM et 2*40 Go de disque SSD suffit Ă  faire tourner une typologie de cluster Ă  base de Spark, Hadoop, Tez, Hive avec un niveau de performance acceptable. 

S3

Le service de stockage historique est utilisé pour stocker les logs d’EMR, ainsi que les données froides en entrée et en sortie du cluster. Il est enfin utilisé pour stocker les Notebooks Zeppelin si on utilise ce composant. Ajouté à ces usages, on peut l’utiliser pour stocker les données d’HBase  sans HDFS.

Amazon Machine Image (AMI)

Il s’agit des images de machines utilisées pour peupler notre cluster. L’utilisation de l’AMI AWS permet de ne pas ajouter de coûts supplémentaire de licence.

Dynamo DB

Le composant EMR FS, dont l’utilisation permet de s’assurer de la cohérence et de la localisation des données sur S3, utilise Dynamo DB pour stocker en interne ses métadonnées. Avec lui, EMR consomme facilement les données de S3.

Relational Database Service (RDS)

RDS est fortement recommandé pour stocker les données non reconstructibles telles que :

  • les informations du mĂ©ta store Hive
  • les Workflows Oozie
  • les mĂ©tadonnĂ©es de Hue

Grâce à cela, même si j’utilise un cluster éphémère mes métadonnées ne seront pas perdues.

Elastic Block Store (EBS)

Les instances EC2 sont livrĂ©es avec des capacitĂ©s disque diffĂ©rentes. Par exemple, pour des instances de type m3.xlarge, elles reposent sur deux disques SSD de 40 Go. Dans un contexte EMR, une partie de cet espace disque est dĂ©diĂ© au système d’exploitation et le reste est dĂ©diĂ© Ă  HDFS. La capacitĂ© d’HDFS est ajustable via l’ajout d’EBS supplĂ©mentaires aux instances.

Architecture cible 

L’architecture cible choisie est simple et n’aborde pas les aspects sĂ©curitĂ©. Il conviendra d’ajouter ces composants en amont de l’architecture (bastion, Reverse proxy, Key Management Service, Security group…).

La figure ci-dessous présente de manière macroscopique les composants entrant en ligne de compte  :

Architecture cible

On y retrouve les Ă©tapes type d’opĂ©rations que nous allons rĂ©aliser pour un traitement batch :
  • Stockage : Les donnĂ©es sont dĂ©posĂ©es sur S3 avant l’instanciation. Notre cluster EMR log Ă©galement son Ă©tat sur S3.
  • Data management : Toutes les tables crĂ©Ă©es par l’utilisateur dans Hive, par exemple, sont stockĂ©es dans RDS. Hive ou Presto utilisent ce que l’on nomme le schema on read, et par consĂ©quent, peuvent poser un schĂ©ma sur de la donnĂ©e prĂ©sente dans S3.
  • Traitement : EMR consomme S3, et s’aide d’EMR FS pour s’assurer de la data locality en utilisant DynamoDB. DiffĂ©rents types de processing peuvent ĂŞtre rĂ©alisĂ©s via des outils tels que Hive, Spark, Zeppelin, Pig, Presto, HBase. Le cluster EMR expose un ensemble de WebUI.
  • Stockage & exposition : Les rĂ©sultats du traitement sont stockĂ©s dans S3. 
Préparation

Nous allons maintenant nous poser les bonnes questions pour préparer un cluster conforme à nos besoins.

De quelles données ai-je besoin ? Quel niveau de confidentialité ?

Avant d’instancier un cluster pour une utilisation en mode batch, il convient de copier les donnĂ©es utiles dans S3 et d’en permettre l’accès Ă  notre futur cluster EMR pour qu’il les consomme. De nombreuses solutions existent pour amener la donnĂ©e sur S3. Vous en trouverez quelques exemples dans ce retour d’expĂ©rience d’un workshop Big Data. La manipulation de donnĂ©es implique le respect des diffĂ©rentes règles relatives Ă  leur confidentialitĂ© et Ă  leur protection. A titre d’exemple, les mĂ©canismes de chiffrement des donnĂ©es S3 peuvent ĂŞtre activĂ©s. EMR FS supporte ces mĂ©canismes Ă  condition d’en utiliser qu’un seul simultanĂ©ment.

Au niveau europĂ©en, la lĂ©gislation applicable « General Data Protection Regulation » (GDPR) pourra ĂŞtre respectĂ©e dès son entrĂ©e en vigueur en mai 2018, c’est du moins ce Ă  quoi s’engage AWS.

De quelles type d’authentification utilisateur ai-je besoin ? De quelle manière manière dois-je gĂ©rer les autorisations ?

Les mĂ©canismes habituels d’authentification utilisateur comme Kerberos ou encore LDAP peuvent ĂŞtre activĂ©s. Les « Role Based Access Control » (RBAC) avec l’outil Apache Ranger peuvent ĂŞtre implĂ©mentĂ©es ce qui permettra de gĂ©rer finement les accès utilisateur Ă  vos donnĂ©es et de savoir qui y a accĂ©dĂ©.

Quelle distribution choisir ?

Le service EMR embarque par défaut une distribution Hadoop composée des différents outils de l’écosystème Hadoop. La figure ci-dessous extraite de la documentation présente les différentes releases d’EMR avec les versions des outils correspondant :

EMR Releases

Les outils qui composent une release d’EMR sont déclinés en version Open source pure ou en version spécifique pour EMR.

Un exemple illustrant ce point avec la bibliothèque « hadoop command line client » disponible en version 2.7.3-amzn-2 sur EMR. Dans ce cas, il s’agit d’une version spĂ©cifique pour EMR car sa signature est suffixĂ©e « amzn-2 ». Le choix de la distribution est motivĂ© par les versions des composants que nous souhaitons utiliser, leurs disponibilitĂ© au sein d’une release EMR et la stabilitĂ© vĂ©rifiĂ©e de l’ensemble. Il convient de ne pas prendre la toute dernière release d’EMR mais l’une des plus rĂ©centes. Pour conclure ce choix, un cluster EMR peut ĂŞtre Ă©galement instanciĂ© avec diffĂ©rentes versions de la distribution MapR. Le prĂ©sent article ne couvre pas ce mode de fonctionnement.

De quels outils ai-je réellement besoin ?

À partir de la version EMR choisie, il faut sélectionner la liste des outils que nous allons utiliser. Si nous utilisons uniquement les outils nécessaires, notre cluster démarrera beaucoup plus rapidement. Par défaut, la console AWS propose quatre topologies de cluster. Via le client AWS en ligne de commande (aws-cli) ou au sein des options avancées, nous pouvons construire une topologie personnalisée.

La flexibilitĂ© d’EMR permet d’installer un composant Ă  postĂ©riori avec une commande du type :

aws emr install-applications --cluster-id j-2A6HXXXXXXL7J --apps Name=Hive
Ai-je besoin d’un cluster permanent ou éphémère ?

Short long

Nous pouvons lancer deux types de cluster EMR :

Les clusters « long running » sont permanents et ne s’Ă©teignent pas sauf action spĂ©cifique de son propriĂ©taire. Les clusters Ă©phĂ©mères quant Ă  eux rĂ©alisent une ou plusieurs étapes et s’Ă©teignent une fois ces dernières terminĂ©es. Les Ă©tapes sont des mĂ©canismes complets qui peuvent rĂ©aliser un ensemble d’actions comme par exemple un job Spark. On peut aussi ajouter des Ă©tapes sur les clusters « long running ». Historiquement, il existait une limitation Ă  256 Ă©tapes maximum sur un « long running » cluster. Cette règle est maintenant transformĂ©e en 256 Ă©tapes simultanĂ©es maximum sans limitations du nombre total d’Ă©tapes.

Le diagramme ci-dessous extrait de la documentation AWS présente les différents états d’un cluster EMR quelque soit son type.

Aws diagramme

On constatera que ce qui diffĂ©rencie le « long running » de l’Ă©phĂ©mère sur ce diagramme est le fait que le long running reste dans l’Ă©tat WAITING jusqu’Ă  une action de terminaison du cluster. Un cluster Ă©phĂ©mère quant Ă  lui rĂ©alise ses Ă©tapes et passe ensuite au statut SHUTTING_DOWN puis COMPLETED.

Quelle est la volumétrie des données à traiter ? Quel type de traitement vais-je réaliser ?

La volumétrie de données à traiter est un facteur déterminant sur le sizing du cluster. Plus, il y a de données en entrée de mon traitement et plus je vais avoir besoin de ressources si je souhaite que l’ensemble de mon jeu de données soit traité en parallèle et rapidement.

Est-ce que mon traitement est CPU, IO ou Memory bound ? En fonction de ces critères, je vais choisir le type d’instance EC2 qui vont peupler mon cluster.

Un cluster EMR est composé de trois groupes d’instance(s) EC2 :

  • Master : Noeuds maĂ®tres ou noeuds de management. C’est sur ce type de noeud que des processus « Master » tels que le namenode de HDFS ou le ressource manager de YARN s’exĂ©cutent.
  • Core : Ce sont les workers de notre cluster et ce sont eux qui exĂ©cutent le processus DataNode pour HDFS et Node Manager pour YARN.
  • Task : Noeuds de pur calcul, ils peuvent exĂ©cuter des processus de type Node Manager pour YARN mais ne stockent pas les donnĂ©es d’HDFS.

La figure ci-dessous présente un exemple de topologie de cluster EMR incluant des noeuds core et master.

EMR.png

Quel est mon budget ?

Le budget est bien entendu primordial et ce d’autant plus lorsqu’on dĂ©marre une horde de machines EC2. Avant d’utiliser le service EMR, il est bon d’exploiter la calculatrice pour estimer le coĂ»t de facturation en se basant sur le coĂ»t horaire des machines. Il faut aussi tracer la facturation liĂ©e Ă  l’instanciation du cluster en le « taggant ».

Afin de limiter les coûts, rien de tel que les instances ponctuelles, également nommées instances spot. On peut composer un cluster EMR uniquement à base d’instances ponctuelles. Pour ce faire, il faut se renseigner sur le cours historique de l’instance ciblée dans la zone de disponibilité cible. Si on propose un prix légèrement au dessus de l’historique du cours, on peut diviser par 5 le coût de l’instance à l’heure !

Voici une commande Ă  adapter permettant de se renseigner sur le cours d’une instance de type « m3.2xlarge » depuis le 25/07/2017 Ă  7h08 dans l’AZ eu-west-1c

  aws ec2 describe-spot-price-history --instance-types m3.2xlarge  --start-time 2017-07-25T07:08:09 --availability-zone eu-west-1c


Autre facteur de coût : le stockage EBS associé à chaque machine. Hadoop repose historiquement sur HDFS qui lui-même repose sur des disques configurés en JBOD. En environnement AWS EMR, le stockage EBS est utilisé pour stocker les données temporaires de nos phases de processing et également pour HDFS. Nous pouvons associer plusieurs volumes EBS à nos instances, ce qui aura pour effet de démultiplier les I/O pour l’accès à ces données. Quoi qu’il arrive à nos volumes EBS sur EMR, ils sont éphémères et non reconstructibles. C’est également le parti pris par HDFS avec sa gestion des réplicats permettant de s’affranchir de la perte d’un disque ou d’une machine.

Quelle est ma scaling policy ?

Atout considĂ©rable d’EMR, l’augmentation dynamique de la capacitĂ© de traitement du cluster. Nous pouvons augmenter la capacitĂ© du cluster (Scale Out) ou la diminuer (Scale In) en fonction de multiples mĂ©triques du cluster (mĂ©triques remontĂ©es par CloudWatch). Ă€ titre d’exemple, nous pouvons engendrer un Scale Out du cluster si la mĂ©moire disponible dans YARN est infĂ©rieure Ă  15 % du total disponible. Les nĹ“uds master quant Ă  eux ne sont pas scalables, les politiques de scale In/Out sont uniquement rĂ©alisables sur les noeuds de type Core ou Task. CloudWatch va surveiller les mĂ©triques de YARN et agir sur EMR au travers du rĂ´le AmazonElasticMapReduceAutoScaling.

La figure ci-dessous présente la stratégie par défaut pour l’Auto Scaling d’EMR.

Auto Scaling EMR

Les stratĂ©gies de scaling sont cumulables. Il faut par consĂ©quent veiller Ă  ce qu’elles ne se mordent pas la queue !!

Dois-je adapter la configuration des services ?

Toutes les configurations par dĂ©faut des composants Hadoop sont modifiables dès l’instanciation du cluster. Par exemple, nous pouvons modifier les paramètres par dĂ©faut des services Hadoop tels que YARN ou Spark. Ces actions sont possibles directement dans l’aws cli avec l’utilisation de l’option --configuration ou la rĂ©fĂ©rence Ă  un fichier json dĂ©posĂ© au prĂ©alable sur S3. Une troisième mĂ©thode consiste Ă  passer par la console pour modifier les options de configuration des services. Les diffĂ©rents niveaux de configuration des services Hadoop sont modifiables qu’il s’agisse d’un fichier hive-site.xml ou d’une propritĂ© du fichier hue.ini.

Voici quelques exemples d’actions de configuration qu’il est bon de rĂ©aliser :

Premier exemple, configurer Hive pour qu’il utilise une base de donnĂ©es RDS MariaDB ainsi que quelques propriĂ©tĂ©s au sein du fichier hive-site.xml.

{
  "Classification": "hive-site",
  "Properties": {
    "hive.server2.authentication": "NOSASL",
    "hive.enforce.bucketing": "true",
    "hive.support.concurrency": "true",
    "javax.jdo.option.ConnectionUserName": "<DB_USER>",
    "hive.txn.manager": "org.apache.hadoop.hive.ql.lockmgr.DbTxnManager",
    "javax.jdo.option.ConnectionDriverName": "org.mariadb.jdbc.Driver",
    "javax.jdo.option.ConnectionPassword": "<DB_PASSWORD>",
    "hive.exec.dynamic.partition.mode": "nonstrict",
    "javax.jdo.option.ConnectionURL": "jdbc:mysql://<DB_HOST>:3306/hivemetastoredb?createDatabaseIfNotExist=true",
    "hive.compactor.initiator.on": "true",
    "hive.compactor.worker.threads": "1"
  },
  "Configurations": []
}

Ceci aura pour effet de garantir la non perte des métadonnées des tables déclarées dans Hive dans le cas où le cluster disparaît.

Deuxième exemple, mais d’un niveau diffĂ©rent, configurer Hue pour qu’il utilise une base de donnĂ©es RDS MariaDB. Dans le prĂ©cĂ©dent exemple, on configurait les propriĂ©tĂ©s d’un service Hadoop (Hive) dans la zone Properties. Ici, on modifie la zone [desktop] et sa sous zone [[database]] Ă  l’aide du JSON suivant.

{
  "Classification": "hue-ini",
  "Properties": {},
  "Configurations": [
    {
      "Classification": "desktop",
      "Properties": {},
      "Configurations": [
        {
          "Classification": "database",
          "Properties": {
            "password": "<DB_PASSWORD>",
            "engine": "mysql",
            "port": "3306",
            "host": "<DB_HOST>",
            "name": "<DB_NAME>",
            "user": "<DB_USER>"
          },
          "Configurations": []
        }
      ]
    }
  ]
}


Un troisième exemple, consiste Ă  configurer Zeppelin pour qu’il stocke les Notebooks dans S3 :

{
  "Classification": "zeppelin-env",
  "Properties": {},
  "Configurations": [
    {
      "Classification": "export",
      "Properties": {
        "ZEPPELIN_NOTEBOOK_S3_BUCKET": "<BUCKET_S3>",
        "ZEPPELIN_NOTEBOOK_S3_USER": "<USER_S3>",
        "ZEPPELIN_NOTEBOOK_STORAGE": "org.apache.zeppelin.notebook.repo.S3NotebookRepo"
      },
      "Configurations": []
    }
  ]
}

Grâce à cette configuration, les Notebooks développés sur Zeppelin seront sauvegardés dans S3.

Actions d’amorçage ?

Les actions d’amorçage sont lancĂ©es avant l’exĂ©cution des traitements sur le cluster et sont optionnelles. Elles permettent entre autre, d’installer des paquets supplĂ©mentaires sur les machines, d’ajouter des utilisateurs, … Un ensemble de scripts stockĂ©s sur S3 et appelables en tant qu’action d’amorçage est mis Ă  disposition par AWS.

Let’s go

Nous sommes maintenant prĂŞts pour dĂ©marrer un EMR . Cette action peut se faire de diffĂ©rentes manières : pour l’illustrer nous allons prendre un besoin de cluster EMR fictif dĂ©taillĂ© dans le tableau ci-dessous :

CHOIX A REALISER CHOIX EFFECTUE Type de cluster Long running Release EMR emr-5.7.0 Sous réseau subnet-XXX Groupe de sécurité du master sg-XXXX Groupe de sécurité des machines core sg-XXXX Outils Hadoop

Hue

Spark

Hive

Zeppelin

HCatalog CaractĂ©ristiques du groupe d’instances master 1 instance m3.xlarge de type ponctuelle avec un prix horaire souhaitĂ© de 0.10$ CaractĂ©ristiques du groupe d’instances core 2 instances m3.xlarge de type ponctuelle avec un prix horaire souhaitĂ© de 0.10$ Configuration de EMR FS

fs.s3.consistent.retryPeriodSeconds Ă  10 secondes
fs.s3.consistent Ă  true
fs.s3.consistent.retryCount Ă  5
fs.s3.consistent.metadata.tableName Ă 
EmrFSMetadata
Auto Scaling Utilisation du rĂ´le EMR_AutoScaling_DefaultRole Actions d’amorçage Aucunes Taille du volume racine EBS 10 Go pour le volume root (ce qui aura pour impact de dĂ©dier le reste Ă  HDFS). RĂ´le pour le service EMR dans IAM EMR_DefaultRole RĂ´le pour les instances EC2 dans IAM EMR_EC2_DefaultRole Nom du cluster my-first-emr Contrainte de scale Down TERMINATE_AT_INSTANCE_HOUR RĂ©gion de facturation eu-west-1 RĂ©pertoire de log dans S3
s3n://aws-logs-XXX-eu-west-1/elasticmapreduce/


La commande d’exemple suivante (Ă  adapter) utilisant l’aws cli suffit Ă  dĂ©marrer un cluster :

aws emr create-cluster \
      --applications Name=Hadoop Name=Hue Name=Spark Name=Hive Name=Zeppelin Name=HCatalog \
      --ec2-attributes  '{"KeyName":"bbo_emr","InstanceProfile":"EMR_EC2_DefaultRole","SubnetId":"subnet-XXX","EmrManagedSlaveSecurityGroup":"sg-XXXX","EmrManagedMasterSecurityGroup":"sg-XXX"}' \
      --release-label emr-5.7.0 \
      --log-uri 's3n://aws-logs-XXX-eu-west-1/elasticmapreduce/' \
      --instance-groups '[{"InstanceCount":1,"BidPrice":"0.10","InstanceGroupType":"MASTER","InstanceType":"m3.xlarge","Name":"Groupe d instances maître - 1"},{"InstanceCount":2,"BidPrice":"0.10","InstanceGroupType":"CORE","InstanceType":"m3.xlarge","Name":"Groupe d instances principal - 2"}]' \
      --configurations '[{"Classification":"emrfs-site","Properties":{"fs.s3.consistent.retryPeriodSeconds":"10","fs.s3.consistent":"true","fs.s3.consistent.retryCount":"5","fs.s3.consistent.metadata.tableName":"EmrFSMetadata"},"Configurations":[]}]' --auto-scaling-role EMR_AutoScaling_DefaultRole      \
      --ebs-root-volume-size 10 \
      --service-role EMR_DefaultRole \
      --enable-debugging \
      --name 'my-first-emr' \
      --scale-down-behavior TERMINATE_AT_INSTANCE_HOUR \
      --region eu-west-1


Quand on connaĂ®t la multitude d’opĂ©rations Ă  rĂ©aliser pour mettre en service un cluster Hadoop traditionnel, pouvoir le faire en une commande est exceptionnel. Une fois la commande exĂ©cutĂ©e, le cluster passe par les diffĂ©rents Ă©tats dĂ©crits plus haut. L’Ă©tat du cluster est visible via les diffĂ©rents moyens d’interfaçage avec AWS. Dans le cas d’un long running cluster, les interfaces utilisateur Zeppelin et Hue sont opĂ©rationnelles au bout d’une dizaine de minutes seulement !

Pour y accéder, deux possibilités :

  • Connexion SSH au master et crĂ©ation de tunnels vers les diffĂ©rentes WebUI disponibles.
  • Connexion SSH au master incluant un proxy socks avec dynamic port forwarding.
Une fois cette connexion SSH Ă©tablie, depuis Hue, on peut maintenant accĂ©der aux donnĂ©es de S3 et en produire de nouvelles Ă  l’aide d’Hive. Les possibilitĂ©s sont mutliples et pour citer un dernier exemple, on peut lancer des traitements avec Spark depuis l’interface Zeppelin ou directement en ligne de commande. Voici un exemple de lancement d’un jar Spark (calcul de Pi du jar spark-examples) en ligne de commande sur un cluster « long running » :
aws emr add-steps --cluster-id j-2AXXXXXXGAPLF --steps Type=Spark,Name="Spark Program",ActionOnFailure=CONTINUE,Args=[--class,org.apache.spark.examples.SparkPi,/usr/lib/spark/lib/spark-examples.jar,10]
Infra as Code (IaC)

Le code de l’infrastructure EMR construite peut vivre au sein de vos projets Data et suivre ses propres releases. Il existe plusieurs possibilités pour créer, tester et déclencher le code associé à notre infrastructure.

Voici deux outils bien connus des profils Devops

  • Terraform : Outil multi fournisseurs de Cloud dĂ©veloppĂ© par HashiCorp, il permet de planifier, provisionner et dĂ©truire notre infrastructure dĂ©crite dans des fichiers Ă  l’extension .tf. Il est très complet mais il n’a pas nativement toutes les fonctionnalitĂ©s AWS spĂ©cifiques Ă  EMR. Heureusement, des JIRA sont en cours de rĂ©solution pour les prochaines versions et il est possible de dĂ©velopper ses propres composants. Un exemple de configuration pour EMR est fourni.
  • CloudFormation : IntĂ©grĂ© Ă  AWS uniquement, il permet d’Ă©laborer une infrastructure et de la dĂ©crire sous forme JSON ou YAML. Cette infrastructure « Cloud formĂ©e » peut ĂŞtre ensuite construite via les diffĂ©rents moyens d’interagir avec AWS, mais Ă©galement avec un outil comme Ansible. De par sa disponibilitĂ© au sein de la constellation des services Amazon, CloudFormation interagit facilement avec EMR.
Flexible, facile et complet pour un besoin Hadoop rapide

EMR est une solution très flexible que l’on peut mettre facilement en service. Elle adresse un nombre important de cas d’utilisation et contient les dernières évolutions de l’écosystème Hadoop. Les avantages à l’utiliser sont très nombreux. En résumé, il n’y a pas de freins à l’utiliser excepté son prix et sa forte adhérence à AWS.

Sur du long terme, les coûts de fonctionnement peuvent être ramenés au strict minimum via l’utilisation des instances ponctuelles et des clusters éphémères.

Plusieurs alternatives à EMR existent. Elles feront l’objet d’articles dédiés. Parmi ces solutions, certaines permettent de réduire encore la facture de l’infrastructure Hadoop mais ne sont pas aussi flexibles qu’EMR et amènent une gestion fine des composants.

Catégories: Blog Société

XEBIA ACCUEILLE LE MEETUP WOMEN WHO GO PARIS

lun, 09/11/2017 - 08:58

 

Lundi prochain, 11 Septembre, Xebia accueillera à partir de 19h le meetup Women Who Go, au 156 boulevard Haussmann, 7e étage.

Le but de ce meetup est d’aider les personnes qui souhaitent apprendre ou pratiquer le langage Go.

Nous allons dĂ©velopper en Go ensemble au travers d’exercices de type Kata, cela sera aussi l’occasion de tester dep, le futur standard pour la gestion de dĂ©pendances des programmes en Go .

Pour vous inscrire, rendez-vous sur le meetup Women Who Go Paris.

 

 

Catégories: Blog Société

Revue de Presse Xebia

jeu, 09/07/2017 - 15:50

revue de presse Xebia
La revue de presse hebdomadaire des technologies Big Data, DevOps et Web, architectures Java et mobilité dans des environnements agiles, proposée par Xebia.

Agilité Les neurosciences et le management http://blog.xebia.fr/author/nullhttp://twitter.com/https%3A%2F%2Ftwitter.com%2Fgael_rebmannhttps://thefnublog.com/Par Gaël Rebmann

Cet article de HBR nous fournit une introduction sur l’utilisation des neurosciences dans notre management. Plus que d’utiliser des outils et des règles préétablies (telles que les moving motivators de Jurgen Appelo), les neurosciences nous promettent la possibilité de comprendre le fonctionnement du cerveau et ainsi de mieux cerner les besoins de nos collaborateurs. La maîtrise de cette science permet alors d’améliorer ces outils et ces règles de management. C’est en tout cas ce que nous promet cet article !

Mobilité Comparaison entre ARKit et ARCore http://www.gravatar.com/avatar/e91bf6e478f34fa8c8378386d332ae44http://blog.xebia.fr/author/nullhttp://github.com/mbretonPar Jose Antonio Martin Sanchez

Suite Ă  la prĂ©sentation de ARKit par Apple, Google n’a pas trainĂ© les pieds et il vient de prĂ©senter sa toute nouvelle plateforme de rĂ©alitĂ© augmentĂ©e baptisĂ©e ARCore. BasĂ©e sur la plateforme Tango, elle essaie de contrer l’enthousiasme provoquĂ© par le nouveau framework de la marque Ă  la pomme. Dans cet article, l’auteur Matt Miesnieks dĂ©cortique les points forts et les points faibles de chaque technologie.

ARCore, la réponse de Google face à Apple et son ARKit http://blog.xebia.fr/author/nullhttp://github.com/mbretonPar Souhaib Guitouni

Google va désormais se concentrer sur ARCore et abandonner progressivement le projet Tango.

Avec une flotte de plus de 100 millions d’appareils compatible à la fin de sa phase de bêta, Google vise à démocratiser l’accès à la réalitée augmentée sous sa plateforme Android. ARCore détermine la position et l’orientation du téléphone pendant qu’on le manipule. Les objets virtuels restent ainsi en place il peut aussi détecter les surfaces horizontales, comme les tables ou les sols, où placer les objets virtuels. Il permet même de mesurer la lumière ambiante afin de permettre aux développeurs d’éclairer les objets virtuels d’une manière réaliste

ARCore mesure la lumière ambiante afin de permettre aux développeurs d’éclairer les objets virtuels d’une manière réaliste.

Les applications comme SnapChat vont-elles s’emparer de ces nouveaux supports pour apporter encore plus de réalisme aux utilisateurs ?

BientĂ´t des snaps avec vos dragons domestiques de GOT !

IoT Module LoRaWAN avec ConnectivitĂ© SigFox http://blog.xebia.fr/author/nullhttp://github.com/mbretonPar Yassir Sennoun Murata, un constructeur japonais d’électronique, propose un nouveau module radio qui embarque Ă  la fois une puce LoRaWAN et Sigfox. Avec ce module, il est alors possible de dĂ©velopper un objet connectĂ© communicant avec la technologie LoRaWAN et Sigfox. http://www.vipress.net/module-lorawan-connectivite-sigfox-murata/ DevOps Mise en place d’un SSL en toute simplicitĂ© http://www.gravatar.com/avatar/37a6259cc0c1dae299a7866489dff0bdhttp://blog.xebia.fr/author/nullhttp://twitter.com/nullhttp://github.com/sarahBuissonPar Sarah Buisson

 Voici un tutorial  pour mettre en place rapidement, facilement et gratuitement un certificat SSL/TLS (Secure Socket Layer – vous savez, les url en https avec un petits cadenas ) sur vos serveurs publics, le tout grâce Ă  SSL for Free.

Catégories: Blog Société

FrenchKit 2017, profitez des toutes dernières places disponibles

lun, 09/04/2017 - 16:30

 

En 2016, nous étions fiers d’organiser, en collaboration avec CocoaHeads Paris, la première conférence française dédiée aux développeurs iOS et macOS : FrenchKit. Après le succès de cette première édition, nous ne pouvions nous arrêter là.

Le 22 et 23 septembre prochain aura lieu la seconde édition de la FrenchKit, au Pan Piper dans le 11ème arrondissement de Paris.

Victime de son succès toutes les places ont été déjà vendues! Nous mettons exceptionnellement 10 places supplémentaires en vente, rendez-vous vite sur le site de la FrenchKit pour en profiter.

De nombreux speakers internationaux seront au rendez-vous
  • Plus de 200 participants amoureux de iOS, Swift et Objective-C (mais surtout de Swift).
  • 2 jours entiers de confĂ©rences et de classrooms. Plus d’espace sera proposĂ© cette annĂ©e, notamment le samedi, pour permettre un meilleur dĂ©roulement des classrooms
  • Des speakers de renom venus des quatre coins du monde. Fastlane, Realm, Swiftgen,… ces outils que vous utilisez au quotidien : nos speakers en sont les auteurs !

Vous pourrez ainsi voir et entendre :

Felix Krause

Certainement l’une des plus grandes célébrité de l’univers iOS, Felix Krause est le créateur du très populaire (et très utilisé) Fastlane qui vous permet d’automatiser toutes vos tâches de développement (packaging, signature, testing, …).

Il travaille à plein temps sur des outils open source pour la communauté iOS au sein de Fabric (récemment racheté par Google).

Chris Bailey

Au cours de la Frenchkit 2016, Chris Bailey avait introduit Swift en tant que langage serveur à travers le framework développé chez IBM, Kitura.

Aujourd’hui à la tête du Server APIs Work Group, il a eu l’occasion de participer à de nombreuses initiatives liées au langage d’Apple et à toutes ses implications pour le serveur.

Frenchkit 2017 sera l’occasion pour lui de nous en dire plus sur les dernières évolutions server-side de la plateforme ainsi que sur le groupe de travail officialisé il y a presque 1 an.

Soroush Khanlou

Célèbre blogger via son site khanlou.com (où il aime régulièrement se moquer de UIViewController), Soroush réalise également des podcast sur fatalerror.fm. Il est actuellement consultant iOS à New-York.

Olivier Halligon

Si vous faites partis de ceux ayant perdus de nombreux cheveux à cause de crash à répétition dûs à des erreurs de typo dans vos String (particulièrement avec les Storyboard), Olivier Halligon est certainement l’homme qui vous a permis de dormir sur vos deux oreilles grâce à son outil Swiftgen. Il est très actif dans la communauté open source puisqu’il est également contributeur sur Fastlane et Cocoapods.

 

 

De nombreux autres speakers ont aussi répondu présent, vous pouvez retrouver la liste complète sur le site de la Frenchkit.

Catégories: Blog Société

AWS – Pourquoi devez-vous créer un VPC ?

mar, 08/29/2017 - 16:30

Qu’est ce qu’un VPC ? À quoi ça sert ? Dois-je en créer un ? Par où commencer ? Que de questions techniques pour démarrer un projet AWS.

Le VPC (Virtual Private Cloud) est en effet, l’une des premières briques d’un projet AWS. Il permet de lancer des ressources dans un réseau virtuel isolé. De nombreux services comme EC2, ECS, RDS reposent dessus. Bien que primordial, AWS VPC s’avère assez compliqué à appréhender tant par la richesse des ressources manipulées (table de routage, gateway, subnet …) que par le domaine de compétences qu’il implique. Il est vrai que pour nous développeurs, le réseau n’est pas notre zone de confort !

Tout en démystifiant les VPC et en exposant les éléments pertinents dans le choix de création d’un réseau dédié, cet article fournit un template CloudFormation implémentant les bonnes pratiques d’un VPC pour démarrer sereinement vos projets.

Pourquoi créer son VPC ?

Tout d’abord, pourquoi créer un VPC alors qu’AWS en fournit un par défaut ? Avant de répondre à cette question revenons quelques instants sur la genèse du réseau sur AWS. Il fut un temps où seul EC2-classic existait, un temps que les comptes de moins de 4 ans (créés après le 4 décembre 2013) ne peuvent pas connaître.

En ce temps lĂ , toutes les instances EC2 Ă©taient dans un seul rĂ©seau public avec des adresses IP publiques auto-gĂ©nĂ©rĂ©es. C’était un modèle simple, mais insuffisant pour offrir de l’infrastructure privĂ©e et isolĂ©e. AWS introduisit donc la notion de VPC afin d’offrir un rĂ©seau virtuel configurable par l’utilisateur. EC2-VPC permet par exemple de sĂ©lectionner une plage d’adresses IP, de crĂ©er des sous-rĂ©seaux, de configurer des tables de routage et des passerelles rĂ©seau. C’est une architecture riche, paramĂ©trable, flexible qui apporte nĂ©anmoins une certaine complexitĂ©. C’est pour cela qu’AWS propose un VPC par dĂ©faut qui a l’avantage de comprendre les fonctions avancĂ©es offertes par EC2-VPC, tout en Ă©tant prĂŞt Ă  ĂŞtre utilisĂ©.

 

Plus précisément, dans quel cas utiliser son propre VPC ?
Pour faire simple dans tout projet :

  • impliquant des interconnexions avec d’autres rĂ©seaux (entreprise, VPC peering, VPN)

  • nĂ©cessitant un dĂ©sir accru de sĂ©curitĂ© en isolant des instances dans des sous rĂ©seaux privĂ©s inaccessibles depuis internet.

 

Le VPC par défaut arrive avec un adressage IP prédéfini 172.31.0.0/16 qui entraine des complications dans l’interconnexion avec un VPN d’entreprise en raison de la plage IP imposée. Il s’avère par ailleurs impossible à appairer (peering) avec un autre VPC par défaut. De plus la configuration initiale du VPC par défaut comprend uniquement un sous-réseau public dans chaque zone de disponibilité alors que la pratique courante est de créer des sous-réseaux publics et privés pour isoler au mieux les instances.

Le VPC par défaut est un bon compromis entre la complexité et la sécurité. Il permet de démarrer rapidement sans se poser de question tout en bénéficiant des avantages de EC2-VPC. Mais pour plus de souplesse, la création d’un VPC personnalisé est obligatoire.

Pour faciliter cette tâche souvent complexe, vous trouverez un template CloudFormation dans le paragraphe ”Template CloudFormation”.

Composants d’un VPC

Dans le but de comprendre le template CloudFormation, cette partie est consacrée aux composants clés d’un VPC. Pour les détails techniques, la documentation AWS est en lien.

Sous-rĂ©seaux : plage d’adresses IP dans un VPC. Le bloc d’adresse CIDR (Classless Inter-Domain Routing) est un sous-ensemble du bloc CIDR du VPC. Chaque sous-rĂ©seau doit rĂ©sider entièrement dans une zone de disponibilitĂ© et ne peut pas s’Ă©tendre sur plusieurs zones.

Pour diminuer la surface d’attaque des ressources (instances EC2, base de données …), une bonne pratique consiste à utiliser un sous-réseau public pour les ressources qui reçoivent directement du trafic depuis Internet, et un sous-réseau privé pour les autres.

  • Public : Si le trafic est acheminĂ© vers une Internet gateway, le sous-rĂ©seau est reconnu comme un sous-rĂ©seau public. Dans cette zone, pour avoir accès Ă  Internet, les instances doivent possĂ©der une IP publique ou utiliser un proxy.

  • PrivĂ© : Si un sous-rĂ©seau ne comporte pas de route vers la passerelle Internet, il est reconnu comme un sous-rĂ©seau privĂ©. L’accès Ă  Internet s’effectue grâce Ă  une NAT gateway ou une NAT instance.

NAT gateway : passerelle de traduction d’adresses rĂ©seau pour autoriser les instances dans un sous-rĂ©seau privĂ© Ă  se connecter Ă  Internet tout en empĂŞchant l’initialisation de connexions entrantes provenant d’Internet.

NAT instance : instance EC2 ayant le même objectif que les NAT gateway. Contrairement à ces dernières, elles ne prennent pas en charge le trafic IPV6 et ne sont pas managées ce qui demande donc plus de configuration et de maintenance. Il est maintenant conseillé d’utiliser des NAT gateway.

Internet gateway : composant qui permet la communication entre des instances et Internet.

Template CloudFormation

Chose promise chose due, voici le template CloudFormation que j’utilise pour créer des VPC : essayez le en un clic sur la console AWS. La subtilité réside dans le paramètre “HAMode” qui crée plus ou moins de NAT gateway en fonction de sa valorisation. Bien que les schémas illustrent une région à deux zones de disponibilités, la configuration gère également les régions à trois AZ telle que l’Irlande.

Ce template est inspiré en partie du site cloudonaut.io et est adapté à nos contraintes. Le choix de l’adressage réseau est restreint à 10.X.0.0/16 mais rien n’interdit de l’amender pour prendre en compte des besoins plus riches.

Version High Availability

Chaque zone de disponibilité AZ dispose de sous-réseaux publics et privés. Par défaut (paramètre HAMode = true), une NAT Gateway est créée dans chaque réseau public de chaque AZ. Les tables de routage des sous-réseaux privés sont donc différentes les unes des autres : une pour sortir par la NAT gateway 1 et l’autre par la NAT gateway 2.

Version non High Availability

Dans sa version non HA, une seule NAT Gateway est utilisée pour l’ensemble des Availability Zone. Tout le trafic sortant des sous-réseaux privés est donc routé vers cette dernière. Cela est bien évidemment déconseillé en production car la NAT Gateway devient un SPOF. De plus, en cas d’une défaillance de l’AZ concernée, l’ensemble des sous-réseaux privés n’a plus accès à Internet.

Mais alors, pourquoi créer un VPC en mode non HA ? 

Tout simplement car une NAT gateway coûte cher : 35$ par mois pour une AZ en Irlande, soit la bagatelle de 105$ pour couvrir les trois AZ. Si vous optez pour une isolation complète, à savoir un VPC par environnement (dev, demo, preprod, bench …) la facture peut être salée. Pour ces environnements et selon vos contraintes, il peut être acceptable de troquer de la disponibilité au profit de quelques économies. D’autant plus que les défaillances au niveau des AZ sont rares.

Vous avez à présent les éléments nécessaires pour créer facilement des VPC et ainsi isoler vos applications les unes des autres. En prime, avec le paramètre HAMode = false en développement, faites plaisir à votre portefeuille et ne soyez plus freinés par les coûts.

Catégories: Blog Société

DĂ©veloppement Agile et Craft

lun, 07/31/2017 - 10:39

Vous ĂŞtes dĂ©veloppeur mobile pour un journal d’information bien connu. Les articles paraissent sur un site web et l’application Android correspondante est utilisĂ©e par des centaines de milliers d’utilisateurs. Elle permet de rĂ©agir sur les articles, et les utilisateurs ne s’en privent pas : c’est le théâtre de dĂ©bats d’un haut niveau Ă©motionnel, si ce n’est orthographique.

Mais un matin, aucune rĂ©action postĂ©e depuis l’application ne paraĂ®t plus sur le site. Les avis dĂ©favorables s’accumulent sur le Play Store :

« Impossible de rĂ©agir depuis l’application. Aucune rĂ©action envoyĂ©e depuis l’application ne parvient aux modĂ©rateurs, alors que les rĂ©actions envoyĂ©es depuis le site passent sans problème. » –RaphaĂ«l H.

« Je suis abonnĂ© mais aucun des messages que je dĂ©pose avec mon smartphone ne s’affiche lorsque je commente l’actualitĂ©… » –Michel K.

« […] Censure des commentaires n’allant pas dans le sens des articles, je me suis donc dĂ©sabonnĂ©… […] » –Adrien V.

Cette situation demande d’agir vite et bien. C’est l’occasion d’illustrer une approche de dĂ©veloppement qui mĂŞle agilitĂ© et savoir-faire (craftsmanship).

Voici le comportement de l’application en matière de commentaires :

  • L’application permet de poster un commentaire en rĂ©action Ă  l’article lui-mĂŞme (indicateur response à false)
  • Elle permet de rĂ©pondre au commentaire d’un autre utilisateur (indicateur response à true)

Avant de vous distraire de votre tâche en cours, votre leader technique a pris le temps d’analyser l’anomalie : l’application ne poste pas les commentaires correctement. Le mapping entre l’indicateur response et la valeur envoyĂ©e Ă  l’API est incorrect. C’est un « if » qui a Ă©tĂ© codĂ© Ă  l’envers.

Le code en question rĂ©vèle l’erreur de mapping concernant la valeur du paramètre responseFlag attendu par l’API.

sendReaction(message, item, response);
public void sendReaction(String message, String answeredItem, boolean response) {

    int responseFlag;
    if (response) responseFlag = 0;
    else responseFlag = 1;
                    
    api.postReaction(message, answeredItem, responseFlag);
}
Agilité

Compte tenu de l’importance du bug, vous mettez de cĂ´tĂ© vos dĂ©veloppements en cours. Vous committez vos changements et vous passez sur une nouvelle branche issue de la version de production.

Votre premier rĂ©flexe est d’ouvrir le test unitaire (TU) du code en question. Qui n’existe pas. Damned. Le bug aurait pu ĂŞtre repĂ©rĂ© si un test avait Ă©tĂ© rĂ©digĂ© lors du dĂ©veloppement initial.

Le code est dans une Activity Android. Vous Ă©valuez l’investissement que constitue la rĂ©daction d’un nouveau test unitaire dans cette situation, et vous prĂ©fĂ©rez laisser le TU de cĂ´tĂ© le temps de produire un correctif dĂ©montrable afin de rassurer votre client.

Vous appliquez le correctif qui consiste Ă  inverser les branches du if. Dans l’immĂ©diat, vous privilĂ©giez la correction du bug par rapport au refactoring.

public void sendReaction(String message, String answeredItem, boolean response) {
 
    int responseFlag;
    if (response) responseFlag = 1;
    else responseFlag = 0;
                    
    api.postReaction(message, answeredItem, responseFlag);
}

Vous testez le correctif sur votre poste de dĂ©veloppement, puis vous publiez le code sur une branche du dĂ©pĂ´t de votre organisation. Le leader technique valide vos changements, vous faites le merge dans la branche d’intĂ©gration.

Votre serveur d’intĂ©gration continue met automatiquement Ă  disposition du reste de l’Ă©quipe une version de recette. Votre Ă©quipe pratique le dogfooding : c’est quand les membres de l’Ă©quipe sont les premiers utilisateurs de leur propre application. Cette pratique permet de confirmer l’absence de rĂ©gression dans des conditions rĂ©elles d’utilisation. Vous montrez le correctif Ă  votre client qui confirme la correction.

Jusqu’Ă  maintenant, vous avez respectĂ© les valeurs agiles :

  • Vous avez privilĂ©giĂ© l’interaction avec votre leader technique pour prendre en compte rapidement un bug sensible
  • Vous avez favorisĂ© la remise en condition opĂ©rationnelle de votre application en laissant de cĂ´tĂ© le refactoring et la documentation
  • Vous avez collaborĂ© avec votre client pour corriger l’anomalie sans vous attarder sur la nature du dĂ©veloppement (bug ou Ă©volution)
  • Vous avez adaptĂ© vos prioritĂ©s suite Ă  la remontĂ©e de l’anomalie au lieu de continuer vos dĂ©veloppements en cours
Craftsmanship

Et maintenant ? Le processus minimal est respectĂ©, du point de vue de votre client, vous pourriez donc livrer une nouvelle version hotfix de votre application et passer au ticket suivant, mais votre travail n’est pas terminĂ©. Dans la mĂ©thode sendReaction, au moins un refactoring vous dĂ©mange. Et votre beau correctif n’est toujours pas testĂ© unitairement.

Compte tenu de la simplicité du correctif, vous pouvez tout reprendre du début.

Vous commencez par écrire un test automatisé. Ici, le plus approprié est un test unitaire qui vérifie la logique du if.

Mais avant de pouvoir écrire ce test unitaire, le code doit être repensé. La classe impactée par le correctif est fortement couplée avec le framework Android qui est difficile à simuler dans un test unitaire. Vous avez deux solutions :

  • Mettre en place le framework Robolectric pour simuler le framework Android dans votre TU
  • Appliquer le pattern Passive View pour sortir la logique du if dans une classe sĂ©parĂ©e, qui serait testable facilement car non dĂ©pendante du framework

Vous choisissez la Passive View car vous pensez que Robolectric ralentirait l’exĂ©cution de vos tests, et Ă  cause du dĂ©lai des mises Ă  jour de Robolectric suite Ă  celles du SDK Android.

Dès que le test passe, vous en profitez pour transformer le paramètre response en enum, petit refactoring qui vous démangeait :

public void sendReaction(String message, String answeredItem, CommentType commentType) {

    api.postReaction(message, answeredItem, commentType.getApiFlag());
} 
enum CommentType {

    INITIAL("0"), ANSWER("1");

    private String mApiFlag;

    CommentType(final String apiFlag) {
        mApiFlag = apiFlag;
    }

    public String getApiFlag() {
        return mApiFlag;
    }
}

Vous adaptez votre test unitaire au changement de signature de la méthode sendReaction().

Ensuite vous faites en sorte que votre développement puisse être repris et maintenu facilement par un autre développeur, grâce à une séance de revue de code. En support écrit, vous préparez une pull request détaillée sur GitHub dont la description rappelle :

Le besoin fonctionnel Correction d’un bug au niveau des rĂ©actions La spĂ©cification technique
  • Extraction de la logique dans une classe dĂ©couplĂ©e
  • Inversion du sens du if
Le scénario de test
  1. Brancher l’application sur un environnement de recette
  2. Poster un commentaire sur un article
  3. Poster une réaction à un autre commentaire
  4. Observer qu’ils sont bien reçus par le backend et que leur type est correct

Ce niveau de détail par écrit permet de garder une documentation écrite et indexée au sujet du correctif au cas où un autre besoin impacterait ce périmètre de code.

NB : l’idĂ©al serait d’intĂ©grer la documentation au code afin de la rendre plus « vivante » et pour qu’elle puisse Ă©voluer avec le code. Mais ce type d’approche est coĂ»teux Ă  mettre en place sur du code existant ; vous laissez donc de cĂ´tĂ© ce chantier pour l’instant.

Quelques heures plus tard, la version corrigĂ©e est publiĂ©e sur le Play Store, certains utilisateurs l’ont installĂ©e, et les premières rĂ©actions des utilisateurs arrivent sur les articles. Vous retrouvez enfin leur douce prose, les trolls, la crĂ©ativitĂ© orthographique.

Ici vous avez appliqué votre savoir-faire et respecté les valeurs Craft :

  • Vous avez soignĂ© votre code en le refactorant après avoir appliquĂ© un correctif
  • En ajoutant un test automatisĂ©, vous avez garanti la non-rĂ©gression pour Ă©viter de corriger toujours les mĂŞmes bugs. Ainsi vous pourrez continuer d’ajouter de la valeur.
  • En documentant votre code et en le montrant Ă  un autre dĂ©veloppeur, vous avez favorisĂ© l’appropriation collective du code
  • Vous avez Ă©tabli une relation de partenariat avec votre client en prenant la responsabilitĂ© de soigner l’aspect technique (tests unitaires, refactoring) au delĂ  d’un correctif minimal
Conclusion

Ă€ partir d’une situation vĂ©cue, dans le contexte du dĂ©veloppement mobile, cet article illustre l’application des valeurs agiles et craft.

Dans le contexte d’un bug sensible, cette approche s’appuie sur les valeurs agiles pour prendre en compte les attentes du client en termes de rapiditĂ© de mise au point d’un correctif.

Elle s’appuie aussi sur les valeurs craft pour permettre Ă  la base de code de rester saine et comprĂ©hensible par les autres dĂ©veloppeurs, prĂ©sents et futurs.

Références
Catégories: Blog Société

Superviser mon application Play! avec Prometheus

ven, 07/28/2017 - 14:52

logo

Il nous semble clair que l’industrie de l’informatique s’est finalement mis d’accord sur trois choses :

  1. Nous avons besoin de faire du code de qualité
  2. Il faut intégrer le code de manière continue
  3. Il faut superviser ce que nous installons

Les pratiques du craftsmanship, en particulier le refactoring, couplĂ©es Ă  un ensemble d’outils de test permettent d’affronter le premier. La construction de pipelines d’intĂ©gration avec des usines comme Jenkins, GoCD ou TravisCI permettent d’attaquer le deuxième. Cependant, la supervision, la situation n’est pas aussi claire. Du coup, il existe une grande variĂ©tĂ© de fonctionnalitĂ©s (stack) pour superviser la JVM, suivre des mĂ©triques mĂ©tiers, gĂ©rer des alertes, etc. La popularisation des architectures distribuĂ©es (dont les microservices) n’a fait qu’empirer la problĂ©matique.

Pour résoudre tous ces problèmes, nous avons choisi une stack composée de Prometheus, CAdvisor et Grafana et nous allons vous montrer comment les utiliser pour superviser une application de site web basée sur Play! framework.

Le choix de la stack de supervision

Finalement, nous avons terminĂ© notre application Play!. Nous avons fait nos tests et notre chaĂ®ne d’intĂ©gration continue et l’application est mĂŞme installĂ©e dans l’environnement de UAT (User Acceptance Testing). C’est Ă  ce moment-lĂ  que nous rĂ©alisons que nous n’avons pas pensĂ© Ă  la supervision !

Après une rapide recherche, nous trouvons qu’il existe en fait deux modèles de communication : le push et le pull. Dans le modèle push, l’application monitorĂ©e envoie rĂ©gulièrement ses mĂ©triques Ă  l’outil de monitoring. Typiquement, il existe entre l’application et l’outil de monitoring un agent intermĂ©diaire qui est chargĂ© de la collection des mĂ©triques. Dans le modèle pull, c’est l’outil de monitoring qui connaĂ®t les applications monitorĂ©es et les requĂŞte Ă  une frĂ©quence spĂ©cifique.

En approfondissant notre recherche nous trouvons plusieurs alternatives :

positionnement

Les alternatives 1. Telegraf + InfluxDB

C’est une stack basĂ©e sur une architecture de push.

Telegraf est un agent qui récupère et exporte des métriques vers un système de stockage comme InfluxDB. InfluxDB est une base de données de type time series utilisée pour le stockage de métriques.

Ces deux outils sont en gĂ©nĂ©ral utilisĂ©s avec Kapacitor. Il fait le pilotage des donnĂ©es et la gestion des alertes. Pour exemple, Kapacitor permet d’Ă©valuer une mĂ©trique dans une fenĂŞtre de 5 ms, la compare avec un seuil puis envoie une alerte sur Slack.

InfluxDB

2. Statsd + Graphite

Également, cette stack est basée sur une architecture de push.

Statsd est un agent rĂ©seau (UDP et TCP) qui permet d’Ă©couter des statistiques et de les envoyer vers un autre système comme Graphite.

Graphite est capable de stocker des donnĂ©es de type time series (c’est-Ă -dire qu’elles sont ordonnĂ©es dans le temps) et fournit Ă©galement un langage de requĂŞtage. Il prĂ©sente une approche similaire Ă  celui de Telegraf et InfluxDB. L’ajout des informations complĂ©mentaires est basĂ©e sur la crĂ©ation des nouvelles mĂ©triques. Les deux mĂ©triques suivantes permettent de compter le nombre de requĂŞtes en succès ou en erreur pour le path /login

stats.api-server.login.get.200 -> 93
stats.api-server.login.get.500 -> 45

Un exemple de l’intĂ©gration de graphite se montre comme suit

graphite-grafana

3. Nagios

Cette stack est basée sur un modèle de pull.

Nagios est un outil spĂ©cialisĂ© surtout sur le monitoring de l’infrastructure. Il est donc plutĂ´t utilisĂ© comme une alternative à sensu. Il comporte un nombre important de plugins mais il ne fait pas le stockage des donnĂ©es, nous devons donc recourir Ă  d’autres outils pour gĂ©rer la persistance.

Le monitoring d’une application basĂ©e sur la JVM (comme Play!) se fait typiquement en utilisant JMX ou en s’intĂ©grant avec statsd.

perfdata

4. Prometheus

Encore une autre stack qu’utilise une approche de pull.

Prometheus est un système de monitoring et d’alerting. L’approche pull nous intĂ©resse Ă©normĂ©ment parce que nous pouvons maĂ®triser les donnĂ©es mĂ©tier que nous voulons rendre publiques dans les applications de monitoring. En fait pour Prometheus, la seule contrainte imposĂ©e Ă  l’application monitorĂ©e est d’ĂŞtre capable de produire du texte avec HTTP. Avec cet outil, il est possible d’ajouter des ensembles de clĂ©s-valeurs pour rendre le monitoring plus dynamique. La mĂ©trique suivante est donc parfaitement valide :

http_request_duration_seconds_bucket{le="0.02",method="GET",path="/assets/:file",status="2xx"} 23

Une vision Ă  plus haut niveau sur l’intĂ©gration d’une application avec Prometheus est montrĂ©e dans l’image suivante :

prometheus-grafana

Cet outil va rester notre choix pour le reste de cet article.

La visualisation

Cependant, il nous reste Ă  choisir l’outil pour la visualisation de nos mĂ©triques. Les alternatives les plus utilisĂ©es sont :

  • Kibana + Timelion. Kibana est l’outil de visualisation par dĂ©faut dans Elasticsearch. Timelion permet l’intĂ©gration de timeseries dans Kibana. Ensemble, ces outils aident Ă  la visualisation mais surtout Ă  l’analyse et l’exploration des donnĂ©es au travers de multiples dimensions.
  • Grafana. Cet outil a Ă©tĂ© conçu pour faciliter la visualisation de dashboards complexes basĂ©es sur des sources timeseries.

Dans notre exemple, nous n’avons pas besoin d’explorer les donnĂ©es et nos dashboards ne sont pas destinĂ©s Ă  un utilisateur final. Ce qui nous intĂ©resse est de pouvoir afficher les mĂ©triques, vĂ©rifier l’Ă©tat de santĂ© de notre application et dans le futur, pouvoir crĂ©er des alarmes. Grafana sera par consĂ©quent l’outil choisi pour la visualisation de nos mĂ©triques.

Les mĂ©triques exposĂ©es par l’application basĂ©e sur Play! Framework

Pour pouvoir exposer les mĂ©triques depuis notre application, il nous faut importer une librairie cliente. Nous avons choisi ce client non officiel pour Scala car il s’adapte un peu mieux Ă  la philosophie compile time safe de Scala, mais nous aurions Ă©galement pu utiliser le client officiel. Pour l’utiliser dans le projet il suffit de l’ajouter dans le fichier build.sbt

libraryDependencies += "org.lyranthe.prometheus" %% "client" % "0.9.0-M1"
L’exposition des mĂ©triques Prometheus va rĂ©gulièrement demander Ă  l’application (toutes les 15 secondes par dĂ©faut) ses nouvelles mĂ©triques. Nous devons donc fournir une manière de crĂ©er les mĂ©triques que nous allons calculer. Nous appelons cette classe un MetricBuilder. Ce builder permet la crĂ©ation de tous les objets qui vont stocker la valeur courante pour chaque mĂ©trique (Counter, Gauge, Histogram et autres). Chaque mĂ©trique doit s’enregistrer auprès d’un Registry pour pouvoir ĂŞtre requĂŞtĂ©e le moment venu avec un appel au outputText. L’implĂ©mentation de ces objets est fournie par le client de Prometheus, il suffit de les configurer et les instancier.
class PrometheusMetricBuilder @Inject()(lifecycle: ApplicationLifecycle, implicit val prometheusRegistry: Registry) { 
  def buildOutputText: String = prometheusRegistry.outputText // prints all metric values
  ... // other metrics
}

Nous devons exposer une url avec toutes les valeurs courantes pour chaque mĂ©trique. Nous allons le faire depuis un contrĂ´leur en utilisant l’implĂ©mentation du Registry injectĂ©e dans notre Builder.

@Singleton
class PrometheusMetricsController @Inject()(metricBuilder: PrometheusMetricBuilder) extends Controller {
  def metrics = Action {
    val samples = new StringBuilder()
    val writer = new WriterAdapter(samples)
    writer.write(metricBuilder.buildOutputText)
    writer.close()

    Result(
      header = ResponseHeader(200, Map.empty),
      body = HttpEntity.Strict(ByteString(samples.toString), Some("text/plain"))
    )
  }
}

Nous pouvons exposer ce traitement dans le path que nous souhaitons. L’url /metrics semble ĂŞtre une bonne idĂ©e. Rajoutons-lĂ  Ă  notre fichier routes.

GET     /metrics                    controllers.PrometheusMetricsController.metrics

Nous n’allons pas rentrer dans le dĂ©tail des types de mĂ©triques, le but Ă©tant de rechercher une solution rapide pour les premières mĂ©triques de notre nouvelle application. Nous proposons alors les trois mĂ©triques suivantes :

Les mĂ©triques 1. Le nombre de visites dans l’application

Supposons que nous voulions monitorer le nombre absolu de visiteurs. Notre objectif est de pouvoir nous donner une idĂ©e du succès de notre site. Celui-ci est un nombre qui augmentera toujours. Pour crĂ©er cette mĂ©trique il suffit de construire une instance de type Counter et l’enregistrer auprès d’un Registry de mĂ©triques fourni par le client de Prometheus.

@Singleton
class PrometheusMetricBuilder @Inject()(lifecycle: ApplicationLifecycle, implicit val prometheusRegistry: Registry) {
  ...
  val counter = Counter(metric"play_requests_total", "Total requests.").labels().register
  ...
}

Ensuite, nous pouvons l’utiliser dans notre contrĂ´leur.

@Singleton
class HomepageController @Inject()(builder: PrometheusMetricBuilder) extends Controller {
  def index = Action {
    builder.counter.inc()
    Ok(views.html.index("Your new application is ready."))
  }
}
2. Le nombre d’utilisateurs connectĂ©s

Le nombre d’utilisateurs connectĂ©s est une mĂ©trique qui doit pouvoir s’incrĂ©menter et se dĂ©crĂ©menter par rapport au nombre de connexions et dĂ©connexions, voire des abandons de page. Prometheus appelle ce type de composant un Gauge. Nous devons Ă©galement Ă©couter le hook (l’envoi du message) de finalisation de l’application pour prendre en compte les utilisateurs qui ferment leur navigateur. Pour cela nous avons une instance de l’ApplicationLifecycle qui nous donne un callback lors de l’arrĂŞt de l’application. Nous allons procĂ©der de manière similaire Ă  la mĂ©trique prĂ©cĂ©dente.

@Singleton
class PrometheusMetricBuilder @Inject()(lifecycle: ApplicationLifecycle, implicit val prometheusRegistry: Registry) {
  ...
  val gauge = Gauge(metric"play_current_users", "Actual connected users").labels().register
  lifecycle.addStopHook { () => Future.successful(gauge.dec()) }
}

Par contre, la logique de ce contrôleur est plus complexe car nous devons augmenter la valeur lors du login, et la réduire lors du fermeture de la session.

@Singleton
class SessionController @Inject()(builder: PrometheusMetricBuilder) extends Controller {
  def login = Action {
    builder.gauge.inc()
    Ok("Logged in ...")
  }
  def logout = Action {
    builder.gauge.dec()
    Ok("Logged out!")
  }
}
3. Le temps de réponse par url

Le temps de réponse est typiquement analysé grâce aux échantillons pris pour chaque route disponible dans notre application. Dans la terminologie de Prometheus, ce type de métrique est appelé un histogramme.

Pour effectuer l’Ă©chantillonnage, nous devons crĂ©er un filtre qui met Ă  jour un composant de type Histogram avec les informations suivantes:

  • La mĂ©thode HTTP
  • Le path
  • Le status de la rĂ©ponse
  • Le temps de rĂ©ponse

Il suffit d’ajouter le composant dans notre PrometheusMetricBuilder :

@Singleton
class PrometheusMetricBuilder @Inject()(lifecycle: ApplicationLifecycle, implicit val prometheusRegistry: Registry) {
  ...
  val httpRequestLatency =
    Histogram(metric"http_request_duration_seconds",
      "Duration of HTTP request in seconds")(httpHistogramBuckets)
      .labels(label"method", label"path", label"status")
      .register
  ...
}

Nous pouvons Ă©crire ce filtre comme suit :

class PerformanceFilter @Inject()(implicit
                                  val mat: Materializer,
                                  builder: PrometheusMetricBuilder,
                                  executionContext: ExecutionContext
                                ) extends Filter {
  ...
  def apply(nextFilter: RequestHeader => Future[Result])(
    requestHeader: RequestHeader): Future[Result] = {
    val timer = Timer()
    val future = nextFilter(requestHeader)
    getRouteDetails(requestHeader) match {
      case Some(details) =>
        future.onComplete {
          time(timer) { statusCode =>
            builder.httpRequestLatency.labelValues(
              details.method,
              details.route,
              statusCode)
          }
        }

      case None =>
        // rien Ă  faire ici
    }
    future
  }
}

Une fois notre application exécutée, testons le lien localhost:9000/metrics pour pouvoir vérifier les valeurs de nos deux métriques.

play_current_users 0.0
play_requests_total 1.0
http_request_duration_seconds_bucket{le="1.0E-4",method="GET",path="/",status="2xx"} 0
http_request_duration_seconds_bucket{le="0.005",method="GET",path="/metrics",status="2xx"} 0
http_request_duration_seconds_bucket{le="0.01",method="GET",path="/metrics",status="2xx"} 1

Nous avons un code capable d’exposer des mĂ©triques, mais il faut maintenant se connecter à Prometheus, CAdvisor et Grafana.

Tester en local avec docker-compose

Pour Ă©viter de tout installer en local, nous fournissons un repository Github avec la configuration initiale basĂ©e sur docker-compose qui vous permettra de dĂ©marrer toute l’infrastructure que nous venons de dĂ©crire :

  • Un container pour Prometheus
  • Un container pour CAdvisor
  • Un container pour l’application avec le framework Play!
  • Un container pour Grafana

Pour tout dĂ©marrer, il suffit d’exĂ©cuter :

docker-compose up -d

Une fois terminé, vous devriez avoir quatre containers :

Containers

Ces differents containers sont liés de la manière suivante :

Docker-engine

CAdvisor

Le Container Advisor permet d’exposer la consommation des resources des container docker. Vu que nous allons utiliser Pometheus et d’autres composants dans docker, CAdvisor semble une très bonne idĂ©e car il est nativement capable d’exposer des mĂ©triques sur la consommation rĂ©seau, mĂ©moire et disque vers Prometheus. Si nous allons à  http://localhost:8080/containers/ nous allons voir un rĂ©sultat similaire Ă  celui-ci :

Metrics

La configuration de Prometheus

La configuration de Prometheus est basĂ©e sur un fichier nommĂ© prometheus.yml dans lequel nous devons spĂ©cifier les endpoints de ce que nous allons monitorer. Chacun peut avoir sa propre configuration contenant le target (combinaison hĂ´te et port), le path url oĂą l’application expose ses mĂ©triques, l’intervalle d’Ă©valuation et d’autres options si nĂ©cessaire.

global:
  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
    monitor: 'monitoring-play-app'
scrape_configs:
  - job_name: 'prometheus'
    scrape_interval: 5s
    static_configs:
      - targets: ['cadvisor:8080']
  - job_name: 'playframework-app'
    scrape_interval: 5s
    metrics_path: '/metrics'
    static_configs:
      - targets: ['play-app:9000']

Vu que nous lions les conteneurs entre eux, il est possible d’utiliser le nom de notre container en tant qu’adresse IP. L’exemple prĂ©cĂ©dent permet de monitorer trois services :

  • CAdvisor. Qui tourne dans un container appelĂ© cadvisor sur le port 8080.
  • notre application Play!. De manière similaire, notre application est disponible Ă  l’url play-app:9000.

Pour vĂ©rifier que nos targets sont bien prises en compte il nous suffit de vĂ©rifier directement sur Prometheus Ă  l’adresse http://localhost:9090/targets. Ici, nous utilisons localhost pour parler avec le container parce nous sommes sur linux. Vous obtenez le mĂŞme rĂ©sultat si vous utilisez Docker for mac ou Docker for windows.

Targets

Il est également possible de requêter nos métriques sur http://localhost:9090/graph. Dans cette page nous pouvons :

  • VĂ©rifier que nos mĂ©triques sont bien prises en compte.
  • VĂ©rifier que les mĂ©triques se modifient dès que nous requĂŞtons notre application Play!
  • Tester des opĂ©rations de regroupement (sommes, moyennes, et autres)
 check
  • PrĂ©visualiser nos mĂ©triques
 graph-current

Cependant, ceci n’est pas vraiment un outil de visualisation et pour cela nous avons besoin d’un logiciel spĂ©cialisĂ©.

Grafana

La suite de visualisation de mĂ©triques Grafana va nous permettre de suivre en temps rĂ©el les mĂ©triques de notre application. L’interface est accessible depuis http://localhost:3000.

Nous allons créer une data source pour pouvoir interroger le service de Prometheus, afin de lier nos métriques à la visualisation de Grafana.

Source

Ensuite, nous devons ajouter un dashboard qui affichera les mĂ©triques exposĂ©es des targets de Prometheus. Heureusement, dans le repository Github nous fournissons un dashboard prĂŞt Ă  l’emploi. Il permet la visualisation des mĂ©triques envoyĂ©es par notre application et ceux de CAdvisor. Il suffit alors d’importer le fichier Grafana_Dashboard.json. Une fois installĂ©, nous avons un panel qui montre le rĂ©sultat de nos mĂ©triques de visites et d’utilisateurs connectĂ©s.

data

Nous devons avoir également un histogramme avec le temps de réponse des url de notre application :

response time

De plus, grâce au CAdvisor nos avons des métriques de consommation de mémoire, processeur et disque de tous nos containers :

CPU

Et voilà, nous avons finalement un outil de monitoring intégré à notre application.

Conclusion

Nous avons abordé les différences entre les modèles push et pull pour la communication avec les outils de monitoring, puis nous avons comparé quelques outils et finalement nous avons choisi Prometheus.

Ensuite, nous avons montré comment exposer des métriques sur un endpoint depuis une application basée sur Play! framework. Finalement nous avons montré le résultat final avec un docker-compose contenant entre autre un dashboard Grafana pour le suivi en temps réel des métriques.

Nous pouvons conclure qu’au final, les outils qui permettent d’avoir des mĂ©triques sont maintenant assez simples d’utilisation.

Quelques problèmatiques restent toujours ouvertes comme par exemple la manière d’intĂ©grer de multiples instances de notre application ou l’intĂ©gration d’un système d’alertes. Nous aborderons ces sujets lors d’un prochain article.

Catégories: Blog Société

GopherCon Denver : Retour sur la conference Go

mer, 07/26/2017 - 16:58

http://blog.xebia.fr/wp-content/uploads/2017/07/gophercon_logo_main.png

Les 12,13,14 et 15 Juillet, a eu lieu Gophercon à Denver (Colorado, USA). La conférence la plus importante sur le langage Go.

  • La sĂ©ance du 12 a Ă©tĂ© dĂ©diĂ©e aux ateliers.
  • Les sĂ©ances du 13 et 14 ont Ă©tĂ© dĂ©diĂ©es aux confĂ©rences.
  • Le 15 (Community Day), Ă©tait l’occasion pour la communautĂ© Go de s’exprimer au travers de lightning talks, de tables rondes et de groupes de travail sur des projets spĂ©cifiques (par exemple dep, kops, le langage Go etc). Un espace Ă©tait rĂ©servĂ© pour des communautĂ©s spĂ©cifiques comme gopherdata (tensorflow, gonum, machinebox, pachyderm) ou gobot afin de faire connaitre leurs avancĂ©es ou laisser les participants programmer des « bots » ou « drones » en utilisant des outils Go. Ă€ la fin du dernier jour, il y a eu une table ronde sur la diversitĂ© dans la communautĂ© Go.

J’ai eu l’opportunité d’y aller. Et en plus d’une communautĂ© très inclusive et ouverte, j’ai trouvĂ© des confĂ©rences de qualitĂ©, des projets en croissance et des personnes de tous horizons, ouvertes et bienveillantes.

Dans cet article je vous propose un aperçu de ce que vous avez pu manquer (ou pas, si vous avez eu la chance d’y participer) durant les deux jours de confĂ©rences. Il pourra Ă©galement vous servir de grille de lecture des quelques talks, dont l’information se trouve ici et les videos ici.

Premier jour de conférences Go Reliability and Durability at Dropbox

Tammy Butow, dĂ©veloppeuse d’infrastructure chez Dropbox, a ouvert les sessions avec un retour d’expĂ©rience de l’utilisation du Go chez Dropbox.
 

Elle a racontĂ© qu’ils ont commencĂ© Ă  utiliser le langage pour ses promesses de simplicitĂ© et de performance. Ils ont conçu et dĂ©veloppĂ© plusieurs systèmes avec Go et ont obtenu de très bon rĂ©sultats avec l’intĂ©gration de plusieurs Ă©quipes. La courbe d’apprentissage des nouveaux dĂ©veloppeurs a Ă©tĂ© relativement basse, mais ils ont encore quelques problèmes de « race conditions » dans la gestion des donnĂ©es, qui reste encore très difficile Ă  gĂ©rer.

Tammy a expliquĂ© qu’ils ont une mĂ©thodologie de « chaos engineering » qui consiste Ă  introduire des erreurs sur des noeuds de l’application distribuĂ©e. Cette pratique nous rappelle celle utilisĂ©e par Netflix avec Simian Army.

The Future of Go

Dans ce talk Russ Cox a lancĂ© la conception de Go 2.0. Il a dĂ©crit pourquoi passer Ă  Go 2. L’idĂ©e n’est pas d’abandonner Go 1.X sinon de commencer la conception et la construction de cette nouvelle version parallèlement afin de rĂ©soudre les problèmes de mise Ă  l’Ă©chelle. L’idĂ©e est de respecter la promesse de compatibilitĂ© de Go et de ne pas fragmenter l’Ă©cosystème.

Ensuite, il a confirmé que le cycle de releases de Go ne changera pas.

Finalement, il a formalisĂ© une mĂ©thodologie pour l’intĂ©gration des fonctionnalitĂ©s sur Go. Il s’agit de la manière dont la communautĂ© travaille aujourd’hui :
1. Accumuler de l’expĂ©rience sur Go au travers de son utilisation
2. Identifier et expliquer un problème
3. Proposer une solution
4. Implémenter, évaluer et affiner la solution
5. DĂ©ployer la solution en prod.

Il n’est pas nĂ©cessaire qu’une seule personne fasse toutes les Ă©tapes.

Les conversations pour Go 2.0 ont commencĂ© Ă  ce moment-lĂ . Il faut commencer Ă  rĂ©diger des rapports d’expĂ©riences et Ă  imaginer les nouvelles fonctionnalitĂ©s de Go 2.0

A Go Programmer’s Guide to Syscalls

Cette fois, Liz Rice nous a aidĂ© Ă  comprendre les appels système (syscalls). Elle a dĂ©veloppĂ© en direct un outil strace (un outil de traçage d’appels système) en Go et nous l’avons testĂ© avec un simple « hello world ». 

Valuable Lessons in Over-Engineering the Core of Kubernetes kops

Kris Nova nous a appris une leçon très utile : il faut savoir rester simple. Dans le dĂ©veloppement de l’outil kops (kubernetes), son Ă©quipe a investi beaucoup de temps en essayant de construire un interprĂ©teur de yaml, qui est devenu un langage en soit très difficile Ă  maintenir, tester et peu pratique pour les utilisateurs (il Ă©tait très facile d’introduire des bugs dans la construction du cluster). C’est pour ça, qu’ils ont pris la dĂ©cision d’abandonner ce « nouveau langage » et de se focaliser sur une API qui permet aux utilisateurs de kops de dĂ©velopper leur cluster en utilisant Go.

Go Anti-Patterns

Il y a eu aussi l’espace pour le craft en Go. Edward Muller nous a rappelĂ© certaines mauvaises pratiques ou « bad smells » très communes, dont :

  • Le syndrome du tiny package
  • Premature exportation ou l’exposition des structures niveau package
  • Le mauvais nommage de package et la creation d’un package « utils » Ă  dĂ©faut d’une meilleure idĂ©e de nommage
  • CrĂ©er des structures pour stocker les options ou les configurations
  • L’excès des pointeurs
  • Les if-then-else au lieu des « happy-paths »
  • L’utilisation d’un interface {}, etc.
Deuxième jour de conférences Understanding Channels

Dans la première keynote du deuxième jour, Kavya Joshi nous a appris l’implĂ©mentation des go-channels. Nous avons commencĂ© par examiner comment il y a eu un compromis entre simplicitĂ© et performance, oĂą la simplicitĂ© a Ă©tĂ© sacrifiĂ©e et la performance est assurĂ©e pour le runtime scheduler qui permet aux threads du système d’exploitation, de rester « unblocked » et d’optimiser l’utilisation de mĂ©moire.

My Journey to Go

Ashley Macnamara nous a émues aux larmes avec cette deuxième keynote, où elle nous a raconté comme elle est devenue développeusse Go et développeur évangéliste, après une carrière dans la photographie.
Un exemple Ă  suivre pour toutes les personnes qui veulent devenir dĂ©veloppeurs ou qui sont en reconversion dans l’informatique. Elle nous a Ă©galement rappelé qu’il n’est pas nĂ©cessaire d’ĂŞtre Rob Pike, Dave Cheney ou Jessie Frazelle pour contribuer Ă  Go.

Advanced Testing with Go

Michell Hachimoto nous a prĂ©sentĂ© de bonnes pratiques pour tester nos dĂ©veloppements Go, sur les niveaux d’une mĂ©thodologie de tests et des manières d’Ă©crire un code plus stable.

Parmi les pratiques abordées il a mentionné :

  • Tests unitaires pilotĂ©s par des donnĂ©es
  • La creation des « Tests Helpers » afin d’encapsuler la gestion d’erreurs et le code de rĂ©fĂ©rence
  • L’execution des tests des sub-processus en condition rĂ©el et au travers de « Mocks »
The Fallacies Of Distributed Computing

Michael Hausenblas nous a parlé des « 8 fallacies » (idées fausses) décrites par Peter Deutsch et comment les aborder sur nos projets Go.

  • Le rĂ©seau est fiable
  • Le temps de latence est nul
  • La bande passante est infinie
  • Le rĂ©seau est sĂ»r
  • La topologie du rĂ©seau ne change pas
  • Il y a un et un seul administrateur rĂ©seaux
  • Le coĂ»t de transport est nul
  • Le rĂ©seau est homogène.
The New Era of Go Package Management

Finalement, Sam Boyer nous a parlĂ© d’un nouvel outil pour la gestion de dĂ©pendances de Go : dep. Cette outil  est pensĂ© pour devenir le nouveau standard Go.

Conclusion

Cette expĂ©rience a Ă©tĂ© très enrichissante. C’Ă©tait une Ă©dition riche tant en qualitĂ© des talks qu’en variĂ©tĂ© des sujets, projets et activitĂ©s.

En attendant la prochaine Ă©dition, nous pouvons continuer Ă  contribuer aux projets open source et Ă  aider concevoir la prochaine version de Go!

Goodies

Catégories: Blog Société

Partagez la connaissance

Partagez BlogsdeDeveloppeurs.com sur les réseaux sociaux