1 of 48

Elm, 4 mois et 10k lignes

Loïc Knuchel

2 of 48

Il était une fois...

  • En janvier, je démarrais chez
  • En regardant la base de données j’ai trouvé… plus de 500 tables 😱
  • J’ai donc cherché un outil pour mieux m’y retrouver, rien 😤
  • Du coup je me suis lancé… 🤓

3 of 48

Azimutt

🔎 recherche globale

🗺️ affichage du nécessaire

🔗 navigation par relations

📍 sauvegarde de l’affichage

✨ et bien plus...

4 of 48

5 of 48

Contexte

Mes expériences:

  • 12 ans de code
  • beaucoup de langages: C, HTML, CSS, PHP, jQuery, Java, TypeScript, Scala, Angular, Ionic, React
  • 8 ans de Scala
  • fort intérêt pour l’architecture, le code robuste et le 0 bug

Les contraintes:

  • beaucoup de front-end 🙈

Mes envies:

  • apprendre de nouvelles choses
  • aucune maintenance

6 of 48

Choix de la stack

Candidats:

<= Connu et trop éloigné pour espérer attirer des contributeurs

<= Similaire à Scala

<= Pas assez strict

<= Trop orienté Haskell

<= Très intéressant

<= Intriguant

7 of 48

Elm

8 of 48

Elm ?

Un langage purement fonctionnel construit pour les interfaces web.

  • Fortement typé 💪
  • Tout est immuable 👏
  • Aucun effet de bord 🤔
  • Aucune erreur d’exécution 🤯

9 of 48

Aucune erreur d’exécution ???

🤯

10 of 48

Sérieux ?

11 of 48

La philosophie initiale guide tout

12 of 48

La philosophie de Elm

Construire un écosystème robuste, cohérent et facile à utiliser

pour les années à venir

👌

13 of 48

Intéressant ?

Toujours motivé ?

Système de build

Gestion de packages

Isolation avec JavaScript

Typage fort exhaustif

Immutabilité

Pas de null

Pas de système d’erreur

Peu de fonctionnalités core

Ecosystème à construire

Forte courbe d’apprentissage

Boilerplate

Fonctions pures

Elm

#Robuste #Cohérent #Accessible

14 of 48

Voyons ça de plus près

15 of 48

Elm 😍: la communauté

  • Bienveillante pour les débutants
    • Discourse
    • Slack
    • Twitter
  • Encore petite et accessible

16 of 48

Elm 🤩: tout sur mesure!

  • Gestionnaire de paquets
    • Versions sémantiques garanties
    • Ecosystème petit mais suffisant et très qualitatif
  • Système de build (elm make & elm-live)
    • Clé en main
    • Erreurs dans le navigateur
    • Suppression du code mort
  • elm-test
  • elm-format
  • elm-review
  • elm-book

17 of 48

elm-test 🧪

  • Composabilité
    • Un test est juste un valeur crée par une fonction de test
    • On peut donc les générer ou créer des fonctions plus riches autour
  • Suite de tests incomplète
    • skip & only
  • Property based testing inclus
    • vérifier des invariants à partir de données aléatoires
      • définir des générateurs
      • vérifier les propriétés

18 of 48

elm-test 🧪

  • Property based testing, inclus
  • Suite de tests incomplète
  • Composabilité

test "basic" (\_ -> "id INT" |> Parser.run columnParser |> Expect.equal (Ok { column | name = "id", kind = "INT" }))

testParseTable : String -> SqlStatement -> ParsedTable -> Test

testParseTable name sql result =

test name (\_ -> sql |> Parser.run createTableParser |> Expect.equal (Ok result))

testParseTable "basic"

"""CREATE TABLE users (

id INT

);"""

{ schema = Nothing

, table = "users"

, columns = [ { column | name = "id", kind = "INT" } ]

}

19 of 48

elm-format 🕶️

  • Formate le code Elm 👍️
  • Peut être configuré à la sauvegarde 👍️
  • Pas de configuration
    • Facile à mettre en place 👍️
    • Forte homogénéité 👍️
    • Il faut s’habituer à certains choix 😵‍💫
      • beaucoup d’espace vertical (commentaires)
      • pas de if/else sur une ligne

20 of 48

elm-review 🕯️

  • Annotation de type manquante
  • Visibilité publique nécessaire
  • Non utilisés
    • types
    • paramètres
    • variables
    • dépendances 🎉

21 of 48

elm-book 📖

22 of 48

Elm 🤗: langage simple et minimaliste

  • Très peu de syntaxe
  • Librairie standard minimaliste
  • Paquets “-extra”

23 of 48

Elm 😍: fonctionnel, pur

  • Pas de pièges (null, exceptions, IO)
  • List, Maybe, Result, Task
  • pas de toString

24 of 48

Elm 😉: syntaxe ML

25 of 48

Elm 😥: syntaxe ML

number =

42

number : Int

add : Int -> Int -> Int

add a b =

a + b

paramètres

retour

map : (a -> b) -> List a -> List b

map f xs = ...

List.map String.fromInt [ 1, 2, 3 ]

[ 1, 2, 3 ] |> List.map String.fromInt

👌

26 of 48

HTML template ?

27 of 48

Elm 🤔: HTML en Elm

view : Html msg

view =

div [ class "some-class" ] [ text "Hello Elm" ]

viewHeader : Html msg

viewHeader =

div [ class "header" ]

[ ul []

[ li [] [ a [ href "#" ] [ text "link 1" ] ]

]

]

div : List (Attribute msg) -> List (Html msg) -> Html msg

class : String -> Attribute msg

text : String -> Html msg

28 of 48

The Elm Architecture

29 of 48

Elm runtime

view: Model -> Html Msg

init: Model

Html Msg

update: Msg -> Model -> Model

Msg

Model

30 of 48

Elm runtime

update: Msg -> Model -> Model

Msg

Model

Html Msg

init: Model

view: Model -> Html Msg

31 of 48

Elm runtime

Model

init: Model

view: Model -> Html Msg

update: Msg -> Model -> Model

Msg + Model

Html Msg

DOM

Effets

(js, http, time, random...)

32 of 48

Et côté code ?

33 of 48

type alias Model = Int

type Msg = Increment | Decrement

view : Model -> Html Msg

update : Msg -> Model -> Model

main = Browser.sandbox { init = 0, view = view, update = update }

view model =

div []

[ button [ onClick Decrement ] [ text "-" ]

, div [] [ text (String.fromInt model) ]

, button [ onClick Increment ] [ text "+" ]

]

update msg model =

case msg of

Increment -> model + 1

Decrement -> model - 1

34 of 48

Elm 😅: langage simple et minimaliste

withDefault : a -> Maybe a -> a

map : (a -> b) -> Maybe a -> Maybe b

map2 : (a -> b -> value) -> Maybe a -> Maybe b -> Maybe value

map3 : (a -> b -> c -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe value

map4 : (a -> b -> c -> d -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe value

map5 : (a -> b -> c -> d -> e -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe e -> Maybe value

andThen : (a -> Maybe b) -> Maybe a -> Maybe b

contains : a -> Maybe a -> Bool

exist : (a -> Bool) -> Maybe a -> Bool

filter : (a -> Bool) -> Maybe a -> Maybe a

orElse : Maybe a -> Maybe a -> Maybe a

zip : Maybe a -> Maybe b -> Maybe ( a, b )

zip3 : Maybe a -> Maybe b -> Maybe c -> Maybe ( a, b, c )

andThenZip : (a -> Maybe b) -> Maybe a -> Maybe ( a, b )

toList : Maybe a -> List a

sequenceR : Maybe (Result x a) -> Result x (Maybe a)

fold : b -> (a -> b) -> Maybe a -> b

35 of 48

Elm 😕: un peu trop minimaliste?

  • Pas de types inline 🙁
  • Pas de NonEmptyList, NonEmptyDict => code perso
  • Limite à map5 pour Maybe, Result, List, Random et Fuzz et map8 pour Decode => code perso jusqu’à map12
  • Pas de sucre syntaxique:
    • string interpolation: “Hello “ ++ name ++ “.” pourrait être “Hello ${name}.”
    • destructuring: [a, b] ++ arr pourrait être: [a, b, ...arr]
    • lambda param: Maybe.map(\a -> fn a b) pourrait être Maybe.map(fn _ a)
    • difficile de modifier un record imbriqué
  • Pas encore de pattern classique pour les SPA

36 of 48

Elm 😍: aucun implicite

Le code Elm est écrit uniquement avec des fonctions qui composent.

Aucun mécanisme spécial implicite.

37 of 48

type alias Relation =

{ name : RelationName, src : ColumnRef, ref : ColumnRef }

decodeRelation : Decode.Decoder Relation

decodeRelation =

Decode.map3 Relation

(Decode.field "name" decodeRelationName)

(Decode.field "src" decodeColumnRef)

(Decode.field "ref" decodeColumnRef)

encodeRelation : Relation -> Value

encodeRelation value =

E.object

[ ( "name", value.name |> encodeRelationName )

, ( "src", value.src |> encodeColumnRef )

, ( "ref", value.ref |> encodeColumnRef )

]

38 of 48

Elm 😢: je galère toujours...

  • Type alias: typage structurel
  • Custom types: pas d’attributs nommés
  • elm/http compose mal avec elm/random (exige une commande)
  • Pas de “public uniquement pour les tests”
  • Pas de mode requête/réponse avec les ports
  • Pas de polymorphisme 😭

39 of 48

Grosses surprises

  • Choix courageux de la qualité plutôt que la hype!
    • ML style
    • Construit de zéro, sans raccourci, minimaliste
    • Robustesse plutôt que rapidité
  • Talks focalisées sur l’usage et les principes (cf ressources)
  • Attention portée sur les garanties offertes
  • Exploitation des garanties
    • Optimisations, code mort, compatibilité...

😍

40 of 48

Elm 😍: tient ses promesses

41 of 48

Conclusion

  • Je pensais que c’était impossible
    • 0 erreurs
    • robustesse et cohérence plutôt que rapidité et popularité
    • minimalisme
  • Période d’adaptation nécessaire (ML, html lib…)
  • Super expérience au global

42 of 48

Dois-je me mettre à Elm?

Oui si:

  • tu veux limiter la maintenance et les bugs
  • tu cherches à être productif
  • tu aimes le design et l’architecture
  • tu veux découvrir de nouveaux horizons

Non si:

  • tu aimes avoir du code concis
  • tu aimes les outils qui font “tout”
  • tu veux coder vite
  • tu cherches un outil très utilisé

43 of 48

44 of 48

A quoi m’attendre aux débuts avec Elm?

  • Nouveau paradigme
    • ne pas reproduire ce qu’on connaît => lire et recopier du code Elm open source
    • un certain nombre de choses faciles ailleurs vont être difficiles (état, effets…)

  • Ecrire une fonction pourra être difficile et prendre du temps
    • écrire des sous-fonctions
    • écrire explicitement les types partout

45 of 48

Comment démarrer avec Elm?

  • Doc officielle

  • Contribuer à github.com/azimuttapp/azimutt 🤗

46 of 48

47 of 48

The end

48 of 48

J+15

J+37

J+76