Transition C#.Net vers Scala : un sentier abrupt néanmoins franchissable

Après un peu plus de 3 ans d'expérience dans l'environnement .Net, principalement en tant que software engineer C#, j'ai rejoint Univalence en tant que data engineer pour cette fois-ci travailler avec le langage Scala. Scala est un langage que je n'avais jamais manipulé auparavant et dont je ne connaissais pas grand chose.

Je suis donc parti du monde du langage impératif, où je travaillais sur le back-end et le front-end des projets, pour pénétrer le monde du langage fonctionnel afin de manipuler des données. Il me fallait donc une période de transition pour m'adapter à ce tout nouveau langage pour moi, ainsi qu'à son écosystème. C'est cette expérience que je vais traiter dans cet article où je donnerai mes ressentis, les difficultés auxquelles j'ai fait face et comment je les ai surmontées.

Les difficultés rencontrées

1re difficulté : la syntaxe Scala en elle-même !

La syntaxe, aux premiers abords, peut paraître vraiment étrange !

Par exemple : le type se met à la fin de la déclaration de la variable.

En C# :

int i = 10;

En Scala :

val i: Int = 10
// ou
val j = 10

Ici c'est une question d'habitude. On aurait potentiellement le même ressenti en passant à un autre langage que Scala. Mais, c'est vrai que quand on vient du C#, de C, ou de Java, on comprendra plus facilement des écritures comme l'exemple en C#.

Mais en Scala le langage est fortement "sucré". Ce que je veux dire par là, c'est qu'il existe beaucoup de sucres syntaxiques. C'est-à-dire des syntaxes alternatives, plus simples et plus concises, mais qu'il faut apprendre et connaître.

Exemple :

// si on veut multiplier les entiers entre 1 et 10, on peut l'écrire comme ça
(1 to 10).fold(0)(_ * _)
// ou comme ça
(1 to 10).fold(0)((s, v) => s * v)
// ou comme ça
(1 to 10).fold(0) { case (s, v) => s * v }
// ou tout simplement
(1 to 10).product

Par contre, on retrouve les expressions lambda en Scala, ce qui est un avantage quand on en a déjà fait en C#.

De la programmation impérative vers la programmation fonctionnelle

La plus grande difficulté de cette transition est le passage vers la programmation fonctionnelle. En effet, lors de l'apprentissage du langage, on y est confronté rapidement. Il faut presque complètement changer sa façon de penser le code, comme par exemple essayer d'éliminer au maximum les composantes mutables du code (on ne réaffecte plus les variables préalablement déclarées).

Quand on va un peu plus loin en Scala et en programmation fonctionnelle, on rentre beaucoup dans des notions de mathématiques et l'algorithmie y est plus poussée. J'ai trouvé cela assez amusant de voir que certaines notions apprises en mathématiques lors de mes études étaient utilisées en programmation fonctionnelle, alors que lorsque j'étais dans mon ancien poste je ne m'étais jamais dit que j'allais réutiliser ces notions un jour.

L'écosystème

Quand je parle d'écosystème, je parle des outils autour du langage, des bonnes pratiques, etc. En .Net, l'IDE utilisé est Visual Studio, où le plus souvent nous utilisons les mêmes plugins, librairies et la gestion de code source se fait en général avec Team Foundation Server, intégré à Visual Studio dans les dernières versions. Quant à la documentation, elle est très fournie et on y trouve toujours des exemples. Là où je veux en venir, c'est qu'en .Net nous avons quasiment tout au même endroit et il existe beaucoup de standards. Alors qu'en commençant à me mettre à Scala, nous avons plus de choix, déjà pour l'IDE, où on peut utiliser IntelliJ, Eclipse, Visual Studio Code ou même un simple éditeur de texte !

C'est bien là, un autre facteur de difficulté, qui vaut aussi un certain temps d'adaptation. Il a fallu que je m'adapte à :

  • Git. Car en venant de .Net, il est tout à fait possible de n'avoir jamais fait de Git. J'utilisais surtout Team Foundation Server et dans les projets sur lesquels j'ai été, nous étions sur une base de lock/unlock (lock pessimiste), il y avait aussi moins d'histoire de conflit de merge.
  • Aux raccourcis d'IntelliJ (l'IDE avec lequel j'ai appris Scala), ce qui implique une réadaptation de mes réflexes.
  • Chercher des librairies. Là où certaines fonctionnalités existaient peut être déjà en .Net, elles n'existent pas forcément en Scala/Java, ou il n'existe pas de librairies dites standards. En .Net, on pouvait les chercher et les obtenir directement dans Visual Studio avec NuGet, alors que maintenant nous irions plutôt sur Maven Central et chercher la bonne version d'une librairie pour la mettre dans notre build.sbt.
  • La documentation. en .Net, elle très fournie et détaillé avec des exemples. Mais nous n'avons pas souvent accès au code source. Alors qu'en Scala, nous avons aussi une documentation, mais pas avec autant d'exemple. Il faut parfois explorer le code. Néanmoins, l'avantage c'est que nous pouvons souvent voir ce code source pour comprendre mieux.
  • Au contexte du data engineering. Avec mon ancien poste je développais surtout des clients lourds/légers (donc qui avait une interface graphique ou seulement une console), une couche d'accès aux données et une couche d'abstraction entre les deux. Autrement dit des applications répondant aux design pattern MVVM ou MVC. Maintenant en Scala, je fais des outils sans suivre ces design pattern et surtout sans DAO.

Pour ces difficultés, ce n'était qu'une question d'habitude. Ce que je conseille pour tous ceux qui veulent se lancer dans Scala et la programmation fonctionnelle, c'est de faire ce cours en ligne sur Coursera donné par Martin Odersky, le créateur du langage.

Si vous avez cette chance de travailler avec des personnes confirmées en Scala, ce qui est mon cas au sein d'Univalence, le pair programming m'a permis de progresser énormément. Avoir des exercices réguliers, a aussi été un bon moyen de progression.

Le ressenti après 6 mois

Au bout de maintenant 6 mois à utiliser Scala, je me sens plus à l'aise par rapport à ce qui a été dit précédemment. Je me suis surpris à utiliser des opérations comme map ou flatMap de moi-même, et surtout à réussir à obtenir le résultat voulu à partir de ces opérations. La pente à gravir est assez difficile quand on vient du monde impératif. Et je pense d'autant plus quand on ne vient pas de Java. Mais c'est toujours surmontable. En tout cas, je comprends mieux les avantages de la programmation fonctionnelle.

Lors de cette montée en compétence, j'ai eu la chance d'être mentorés par nos experts. J'ai pu participer à Scala IO 2018 dont nous avons fait un retour ici. J'ai en tout cas remarqué que la communauté Scala est très humble et que mêmes les grands noms sont "accessibles". Cela a en tout cas été un facteur motivant pour en apprendre plus.