My team's using rust. HALP!

My team's using rust. HALP!

I'm online!

Dis, c'est quoi un·e CTO?

Alignement

Vision globale des projets, m'assurer que les gens bossent dans le même sens même s'ils n'ont pas toutes les infos

Priorités

Priorités, pour permettre de l'autonomie choix des technos en plus

Facilitateur·ice

Enlever les obstacles pour que les gens avancent sur leurs projets sans avoir à se poser de questions

Architecte

toujours en collaboration avec l'équipe

Historique Clever

Je suis arrivé en cours de route, pas mal de choix techniques déjà faits.

Java Java Java

Cœur en java

Scala, Scala? Java.

Premières tentatives d'intégrer du scala, finalement restage sur java et réintégration dans l'API principal

Ruby

utilisé comme langage de script sur les VMs. Common practice à l'époque.

NODE ALL THE THINGS

Réécriture d'un orchestrateur from scratch. À l'époque pile la plus simple pour de l'évenementiel. Alternative à ruby pour le scripting

Scala. A lot

Toutes les nouvelles briques web en scala.

Now Rust?

(plus les à côtés)

haskell, elixir, a little bit of go.

 Ça a l'air un peu inefficace ça, non?

pas tant que ça en fait, c'est des briques indépendantes, et à chaque fois on commence petit. On n'a jamais réécrit une brique pour le plaisir.

Donc vous arrêtez scala?

scala a toute sa place comme pile web pas en compétition avec rust sur la partie API web

Ben pourquoi pas go alors?

le système de type c'est fait pour aider. Même si rust et go n'ont pas les mêmes buts, rust répond mieux que go sur le marché de go (déso, pas déso).

Déploiement facile

Pour nous le déploiement d'une app web c'est vraiment pas un problème en revanche on doit outiller les instances et on a besoin de petits binaires faciles à packager et sans dépendances système

"system" language

utile dans le cadre de sozu en particulier: proche du métal. permet de travailler proprement sur la perf

Rust && Scala, main dans la main

même approche de la programmation: modélisation propre à l'aide du système de types découpage en fonctions, implem itérative ??? / unimplemented!. Élimination des problèmes de serde à la fin du monde

TDD, anyone?

Make invalid states unrepresentable. Dans le cas de rust ça inclut aussi les data races

ADTs

case class Peer(
  cidrs: List[String],
  pubkey: String,
  endpoint: String,
  keepalive: Int)
sealed trait WgCommand
case class InitConfig(…)
  extends WgCommand
case class SetPeer(peer: Peer)
  extends WgCommand
case class RemovePeer(pubkey: String)
  extends WgCommand
pub struct Peer {
    pub cidrs: Vec<String>,
    pub pubkey: String,
    pub endpoint: String,
    pub keepalive: u32,
}

struct Rgb (i8, i8, i8)
pub enum WgCommand {
    InitConfig(String, String, String, u32),
    SetPeer(Peer),
    RemovePeer(String)
}

Pattern matching

command match {
    case InitConfig(
        ip,
        pub, priv,
        port) => …
    case SetPeer(peer) => …
    case RemovePeer(pub) => …
}
match cmd {
    WgCommand::InitConfig(
        ip, pubkey, privkey,
        port) => …,
    … 
}

traits


trait Bidule {
    def abstractMethod(t: String): String
    def concrete(t: String): String =
      abstractMethod(t)
}

case class Machin(a: Int) extends Bidule
case class Truc(a: Int) {
    def yolo = a + 42
}
pub trait ProxyClient {
    fn front_socket(&self) -> &TcpStream
    …
}
pub struct Truc {
    pub a: u32,
}

impl Truc {
    fn new() -> Truc {
        Truc { a: 0 }
    },
    fn yolo(&self) -> u32 {
        self.a + 42
    }
}
let a = Truc::new();
let b = &a.yolo();
pub trait FromStr {
    type Err;
    fn from_str(s: &str) ->
      Result<Self, Self:Err>
}

impl FromStr for Bool {
    type Err = ParseBoolError;
    fn from_str(s: &str) -> {
        ...
    }
}
#[derive(Debug,PartialEq,Eq)]
pub struct {}

customDerive all the things

unimplemented!

def myShinyMethod(t: String): String =
  ???
fn myShinyFunction(t: &str) -> String {
    unimplemented!()
}

Result

def doThing(p: Param):
  Either[Error, Value] = …
fn do_thing(p: &Param) ->
  Result<Value, Error> {}

?

for {
    res1 <- op1() // yay scala 2.12,
                  // thanks Simon!
    res2 <- op2(res1)
} yield res2
fn do_things() -> Result<Value, Error> {
    let res1 = op1()?;
    let res2 = op2(res1)?;
    Ok(res2)
}

Not monadic, only for errors

Error normalization

Et le fonctionnel dans tout ça?

Le modèle mémoire de rust est super top, mais assez limitant quand on a l'habitude de scala

Persistent data structures :/

difficile sans GC. Pas si utile que ça finalement grâce au borrow checker

L'impératif, ça passe en fait

avec le borrow checker ça permet d'isoler la mutabilité, et ça passe à peu près en fait. d'ailleurs en scala c'est toléré tant que ça s'échappe pas. Mais en scala c'est dur à prouver (cf la mutabilité de List)

Closures :/

Pour des pures lambdas c'est pas gênant, mais dès qu'on close over un bout de contexte, le borrow checker s'excite

Async :/

Futures. Code encore piégeux, event loop à gérer explicitement. Design pas encore bien fixé, modifications à attendre. Le multithread est jouable dans certains cas, encore une fois grâce au borrow checker

Unboxing & spécialisation

Pas mal de restrictions sur les génériques à cause de l'unboxing, boulot sur la spécialisation. Grosses questions sur l'inférence de type de retour

ipml trait to the rescue

impl trait => abstract boxed / unboxed types not ready yet

No HKTs yet

en cours de discussion https://github.com/rust-lang/rfcs/pull/1598 premier pas

def mapTwice[A, F[_]: Functor](
    v: F[A],
    f: A => A
): F[A] = {
    …
}

Strings. Encore pire qu'en haskell

static str
&str
String
[u8]
[u8,4]
Vec<u8>

C'est normal

On rajoute plus d'invariants, donc le compilo va vérifier plus de choses, mais la contrepartie c'est que plus de programmes légaux vont être refusés. On a donc un tradeoff entre plus de sécurité (moins de corner cases à gérer) et une diminution dans ce qu'on peut faire sans être emmerdé. Bénéfice relatif, tout dépend du projet, de l'équipe, …

Ça vaut le coup de me mettre à rust?

Pour apprendre

C'est toujours bien d'apprendre un nouveau langage basé sur des concepts nouveaux.

Un autre regard sur des concepts du fonctionnel

Il y a pas mal de features des langages fonctionnels qui ne sont pas fondamentalement fonctionnelles et qui ont du sens dans un contexte impératif.

Faire du système / bas niveau en douceur

C'est jouable et moins dangereux qu'en C, du coup ça permet de déstresser

Oui mais au boulot ?

Pour du web?

Pour remplacer des déploiements scala, bof sauf si contraintes particulières. Rien de bien folichon en templating, piles web pas encore bien stables. Je garde mon play, même avec de la DI :-)

Contraintes de déploiement fortes

RAM dépendances, système de déploiement

Exposer simplement une lib C

La FFI en rust c'est quand même plus simple que JNI Routage propre, typage des requêtes, interface sympa. C'est toujours mieux qu'un shell out dégueu

Lib bas niveau / haute perf

Plutôt pertinent pour les langages interprétés qui ont tendance à tomber en C pour avoir des perfs (node, python, ruby). Sur la JVM c'est plutôt rare #JNI

Tooling simple à déployer

Pour du tooling à déployer sur des machines en support d'une appli principale. Fat binary, small footprint

Rust is a better go than go

Rust répond mieux que go aux use cases principaux de go. Pas vraiment grâce à sa gestion de la mémoire, juste parceque le tooling est mieux et que le langage est plus expressif.

Code métier à déployer dans le browser

Très bon fit avec webasm, vu qu'il n'y a pas de runtime. Gros focus de la communauté rust en ce moment

Recap

Langage très intéressant Tradeoffs plus violents que d'habitude Frustrant quand on est habitué à tout boxer et qu'on a un GC

Rust on Clever Cloud

Questions

I'm online!