Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 6 sur 6
  1. #1
    Membre actif

    Profil pro Leroux Sylvain
    Inscrit en
    mai 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Nom : Leroux Sylvain
    Localisation : France

    Informations forums :
    Inscription : mai 2010
    Messages : 36
    Points : 154
    Points
    154

    Par défaut Scala et injection de dépendances

    En surfant un peu, j'ai trouvé l'article suivant:
    http://jonasboner.com/2008/10/06/rea...ection-di.html
    Celui-ci explique que Scala possède au niveau du langage tout le nécessaire pour faire de l'injection de dépendances - donc sans requérir l'utilisation d'un framework spécialisé.

    Je ne vais pas répéter l'ensemble de l'article ici, mais au final, toute la configuration se fait dans un object Scala "ordinaire":
    Code scala :
    1
    2
    3
    4
    5
    6
    7
    8
     
        object ComponentRegistry extends   
          UserServiceComponent with   
          UserRepositoryComponent   
        {  
          val userRepository = new UserRepository  
          val userService = new UserService  
        }
    Et quand à l'utilisation elle se fait le plus simplement du monde, sans avoir à se préoccuper du "câblage" des composants:
    Code scala :
    1
    2
    3
     
      val userService = ComponentRegistry.userService  
      val user = userService.authenticate(..)

    Un argument fort qui est cité est que l'ensemble est statiquement typé. Ce qui permet au compilateur de détecter les incohérences de type - et réduit les surprises au déploiement.


    Que pensez-vous de ce genre de technique? Est-ce que l'argument de la vérification des types donne vraiment un avantage concurrentiel à Scala sur ce point? Est-ce que cela pourrait motiver votre adoption de ce langage?


    - Sylvain

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : mai 2009
    Messages : 98
    Points : 307
    Points
    307

    Par défaut

    Réponse un peu en retard mais bon

    Ce que l'on n'oublie c'est qu'un framework comme Spring permet l'externalisation de la configuration via les fichiers XML. On peut parcourir l'application sans rentrer dans le code.

    Je trouve le couplage trop fort avec une solution comme celle-là. Avec Spring, l'instanciation de l'objet est cachée et on a plus de contrôle sur le cycle de vie de l'objet, tout ça avec un couplage beaucoup plus faible

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : mai 2009
    Messages : 98
    Points : 307
    Points
    307

    Par défaut Contruction monadique des dépendances

    Voici une technique "d'injection de dépendances" que j'utilise dans mes projets Scala. Je la trouve personnellement plus fonctionnelle.

    Tout abord, définissons le trait Functor:

    Code :
    1
    2
    3
    4
     
    trait Functor[F[_]] {
      def map[A, B](m: F[A])(f: A => B): F[B]
    }
    puis la monad Free comme suit

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    trait Free[F[+_], A] {
      def map[B](f: A => B)(implicit F: Functor[F]) = flatMap(a => Done(f(a)))
     
      def flatMap[B](f: A => Free[F, B])(implicit F: Functor[F]) = this match {
        case Done(a) => f(a)
        case More(m) => More(F.map(m)(_ flatMap f))
      }
    }
     
    case class Done[F[+_], A](v: A) extends Free[F, A]
    case class More[F[+_], A](f: F[Free[F, A]]) extends Free[F, A]
    Définissons maintenant nos dépendances:

    Code :
    1
    2
    3
    4
     
    trait Dependency[+A]
    case class GetUserRepository[A](f: UserRepository => A ) extends Dependency[A]
    case class GetUserService[A](f: UserService => A ) extends Dependency[A]
    Nous pouvons maintenant définir un functor pour le trait Dependency:
    Code :
    1
    2
    3
    4
    5
    6
    7
     
    new Functor[Dependency]{
      def map[A, B](d: Dependency[A])(f: A => B) = d match {
        case GetUserRepository(g) => GetUserRepository(x => f(g(x)))
        case GetUserService(g)     => GetUserService(x => f(g(x)))
      }
    }
    Définissons maintenant l'objet Provider qui nous permet de construire "nos dépendances"

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
     
    object Provider {
      def getUserRepository: Free[Dependency, UserRepository] =
        More(GetUserRepository(rep => Done(rep)))
     
      def getUserService: Free[Dependency, UserService] =
        More(GetUserService(ser => Done(ser)))
    }
    Nous pouvons maintenant construire nos dépendances à la demande monadiquement comme cela par exemple:

    Code :
    1
    2
    3
    4
    5
    6
    7
     
    import Provider._
     
    for {
      repo     <- getUserRepository
      service <- getUserService
    } yield ma_fonction(repo, service)
    avec ma_fonction la fonction qui a besoin des dépendances

    Maintenant passons à l'injection à proprement parlé. Définisson le trait Environment comme suit

    Code :
    1
    2
    3
    4
    5
     
    trait Environment {
      val repository: UserRepository
      val service: UserService
    }
    Avec par exemple cette config de dev:

    Code :
    1
    2
    3
    4
    5
     
    object DEV extends Environment  {
      lazy val repository = new UserRepositoryDeDev
      lazy val service = new UserServiceDeDev
    }
    Voici maintenant le fameux "injecteur"

    Code :
    1
    2
    3
    4
    5
    6
    7
     
    @tailrec
    def resolve[A](needed: Free[Dependency, A])(implicit env: Environment): A = needed match {
      case Done(a) => a
      case More(GetUserRepository(f)) => resolve(f(env.repo))
      case More(GetUserService(f)) => resolve(f(env.service))
    }
    En reprenant notre exemple de tout à l'heure, nous avons maintenant

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    import Provider._
     
    val action = for {
      repo     <- getUserRepository
      service <- getUserService
    } yield ma_fonction(repo, service)
     
    resolve(action) // l'injection se passe à ce niveau
    C'est assez dense, mais l'injection de dépendance est un bien grand mot qui peut se résumer à ''Passer un objet en paramètre d'une fonction". Si l'idée vous plait, je pourrais également faire un tutoriel (beaucoup) plus explicatif.

    Que pensez-vous de cette technique ?
    Des points à améliorer ?

  4. #4
    Invité régulier
    Inscrit en
    février 2006
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : février 2006
    Messages : 6
    Points : 7
    Points
    7

    Par défaut

    Citation Envoyé par Yo Eight Voir le message

    C'est assez dense, mais l'injection de dépendance est un bien grand mot qui peut se résumer à ''Passer un objet en paramètre d'une fonction". Si l'idée vous plait, je pourrais également faire un tutoriel (beaucoup) plus explicatif.

    Que pensez-vous de cette technique ?
    Des points à améliorer ?
    Un tutoriel sur la programmation fonctionnelle en Scala? Oui, il serait le bienvenu! Il y en a d'excellents en anglais (par exemple celui d'Eric Torrebore "Essence of Iterator Pattern" ou ceux de Debashih Gosh), mais un en français écrit par un contributeur de Scalaz, ce serait top!
    Si en plus les "monads transformers" sont abordés...(au hasard, ValidationT avec un Writer)

    Benoît

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : mai 2009
    Messages : 98
    Points : 307
    Points
    307

    Par défaut

    A vrai dire les Monad Transformer viennent du monde Haskell.

    Une grande majorité des contributeurs de Scalaz font de l'Haskell. Ils veulent tous avoir les puissantes api provenant de ce langage (compréhensible car elles sont terriblement efficaces)

    Le problème c'est que l'inférence de type en Scala ne fonctionne pas très bien avec ce style et les signatures des méthodes deviennent effrayantes pour les néophytes (tu as du le remarquer quand tu regardes le code source de ValidationT.scala ).

    Un tutoriel sur la programmation fonctionnelle en Scala ? Pourquoi pas mais ça sera que des traductions Anglais => Français ou des ports Haskell => Scala car le sujet a été depuis 2007 beaucoup discuté dans la communauté Scala. Haskell couvre ces sujets depuis au moins une dizaine d'années. Mais pourquoi pas .

    Quand à l'utilisation d'un ValidationT avec un Writer, je veux bien te fournir un exemple qui compile si tu n'arrives pas avec les modifs que j'ai mis sur StackOverflow.

    Il semble qu'il y ait un problème avec le type Id. Depuis la réécriture de scalaz-seven, Id est exprimé comme suit:

    Code Scala :
    1
    2
     
    type Id[A] = A

    Alors que dans Scalaz 6, c'était fait par une conversion implicite vers ce trait

    Code :
    1
    2
    3
    4
     
    sealed trait Id[A]{
      ...
    }
    Il y a peut-être une régression avec certaines typeclass (comme Pointed).

    Si tel était le cas, je proposerais un fix

  6. #6
    Invité régulier
    Inscrit en
    février 2006
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : février 2006
    Messages : 6
    Points : 7
    Points
    7

    Par défaut

    Ce qui pourrait être intéressant, c'est un (ou des) tuto(s) sur les patterns de la programmation fonctionnelle en scala. Un peu du genre de ce que tu as écrit dans cette discussion où tu montres à quoi sert une monad Free.

    Pour en revenir à scalaz, c'est vrai que les signatures des fonctions sont pour le moins redoutables! Mais je pense que cette librairie apporte un vrai confort. Je l'ai expérimenté avec Validation. Quant à notre discussion sur Stackoverflow, je te remercie encore sincèrement de ton aide, mais le code que tu as posté ne compile toujours pas chez moi (j'ai édité le post...)


    Un cookbook sur scalaz serait quand même le bienvenu!

    Benoît

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •