0からScalaを本番導入して感じたこと・考えたこと
はじめに
弊社ではScalaを本番環境に導入して大体1年になる。
導入以前に社内的にScalaに関する知識はゼロだった。
Scalaという言語は巷では色々言われているが愛好者とそれ以外の壁が非常に大きな言語のように思える。
ここはコミュニティの努力によって埋められようとしているが、他の言語に比べてまだまだなのが現状である。
弊社でのScala導入経験に関する情報がその壁を取り払う一助になることを祈る。
導入経緯
Railsの運用コスト
もともとはプロダクトのバックエンドはRailsで書いていた。
Railsは非常に高速にプロダクトを開発できるのだが、長期的に見るとその高速性よりも運用困難性、堅牢性の欠如が目立つようになってきた。
MVCアーキテクチャは複雑なプロダクトを構成するのにはシンプルすぎた。
特にRailsの中核をなすアクティブレコードモデルのせいで問題の分割が難しかった。
じゃあアクティブレコードから責務を切り出していくかとなるのだが、それはもうRailsを使う意味が少なくなっていくという自己矛盾。
またRubyという言語は機能・思想ともに非常に優秀なのだが、動的型付という性質上どうしてもプロダクトの堅牢性が落ちてしまう。
そして動く保証を得るためにテストコードを厚くしていくのだが、テストもタダではない。
実装・運用コストは当然かかる。
正直実装に対してのテストがバカみたいに重い開発には辟易していた。
型があれば自明なこともRubyだとテストしなければ証明できない。
Railsは非常に素晴らしいフレームワークだがユースケースを選ぶことは間違いない。
Scalaの選択
Railsの厳しさが目に付き始めたため、他の言語・フレームワークに移行しようということになった。
約1年前のことである。
そもそも弊社は創業してまだ2年経たないスタートアップであり、一年前はまだまだプロダクトは成長途上であったため移行・書き換えという選択肢があった。
ここは他の成熟したサービスを持つ会社とは違う部分かもしれない。
移行の基準であるがとりあえずは静的型付け言語であるということだった。
その理由はもちろんプロダクトの堅牢性である。
もう一つは分析サービスという側面もあって、なるべく高速で動かしたいということである。
あとは非常に個人的な選択基準だが、書いていて楽しく学びがいのある言語が良かった。
楽しいということはエンジニアにとって非常に重要である。
ここで上がった選択肢はScalaを始めとしてKotlin、Go、PHPあたりだった。
最初はKotlinで行こうという話になった。
しかしKotlinはことサーバーサイドになると弱い。
一応ktorやSpring Bootなどのフレームワークはあるが、いまいちキラー性がないし、運用実績もあまりない。
じゃあGoはという話になったが、書いていて楽しくなさそうなのでやめた。(当時はGoについての知識もあまりなく完全に偏見である。今ではGoも愛用している。Go愛好者の皆さん、すみません。)
最終的にScalaという選択になった。
Playframworkがデファクトなどの理由はあったが、結局決め手は楽しそうだから、という部分は大きい。
一応社内ハッカソンを開いて、そこで使えるかどうかの検証はした。
それでなんとなく行けそうだからじゃあ行くかという話になった。
完全にスタートアップのノリである。
2019 Scala Matsuriの思い出
Scalaで行くかという決断をした直後、時期的に丁度良くScalaの国内カンファレンスであるScala Matsuriがあったのでそれに行った。
その頃はScalaについては文法が多少わかるという程度で関数型については.map
メソッドのこと?という感じだった。
しかしScala MatsuriはDDD、関数型などの結構ディープな話題のセッションばかりで、一年前の自分はさっぱりわからずに講演を聞きながら大ホールで爆睡していた。
参加者には外国の方も多く、国際的なんだなぁという感じだった。
過去にはScala作者のオーダスキ先生もいいらっしゃったこともあるらしい。
でっかくλ
の記号と宗教的な文様が描かれたTシャツを着た外国の方がいて、やばい世界に踏み込んだのかもしれないと思ったのを覚えている。
しかしここでは意外と収穫もあった。
よく意味もわからない中でなぜか型合わせがきついときにはEffみたいな謎の部分だけは覚えていて(もちろんそれが何なのかは全く理解していなかった)、それが後に役立った。
たしかこのスライドである。
今年は去年よりは多少分かるようになっているので、また行きたい。
コミュニティ
コミュニティの雰囲気
Scalaコミュニティはよく怖い人達がいるだの、初心者に優しくないだの言われているがこれは明らかに誤解である。
昔のことはあまり良く知らないが、今は完全な誤解であるということが言えるだろう。
少なくとも自分は1年前に全くの門外漢である状況から今に至るが、この1年で怖い・不快な経験は全く無かった。
逆になんとかScalaを普及させようと情報発信とコミュニティの運営を続ける皆さんには頭が上がらないというのが現状である。
まあしかし外側からみて怖そうに見えるというのもうなずける部分があるのも確かである。
Scalaというのは関数型言語であり、しかもなんちゃってではなくガチガチの関数型である。
やろうと思えばHaskellと同等のことが表現できるし、実際有名なライブラリはHaskellからの移植ということも少なくない。
また学問的な側面も強く出ており、外側から見ると何が嬉しいかわからないモナドや圏論について熱く語っている人たちに見えるだろう。
人は知らないものを恐怖するようにできており、Scalaコミュニティに対する恐怖心の根源は結局はそれなのではないかというのが今の自分の意見である。
とは言ってもScalaを書くなら関数型に習熟することがマストというわけではない。
別に普通のコードもかけるのだ。
関数型を理解すれば便利になる部分があるというだけだ。
これは単なるユーザ自身の選択の問題であって、コミュニティの問題ではない。
Scala Matsuri
ScalaMatsuri 2020 | アジア最大級の Scala のカンファレンス
日本ではScalaのカンファレンスとして毎年Scala Matsuriというものが行われている。
海外の方もたくさん参加されており、国際色が強いというのが特徴である。
ここでは現在のScalaユーザたちがどういう開発をしているか、またどういう課題意識があって、それをどう解決しようとしてるかということが直で感じられる。
特に国内・海外問わずのそこららへんの知見が得られるのが嬉しい。
Scalaの知識レベルによらず非常に有意義なカンファレンスなので、興味のある方はぜひ一度足を運んでみることをおすすめする。
過去のセッションの動画、スライドは過去のホームページにまとめられているので非常に有用。
ScalaMatsuri 2019|日本最大級の Scala のカンファレンス
gitter
scalaのjpグループ。
日本のscala界隈でも有名な人達も普通に質問に答えてくれる。
初心者大歓迎なので質問を投げまくると良いと思う。
コミュニティの人たち
日本のScalaコミュニティの中でも知っておくといいお歴々を雑に紹介していく。
水島さん
日本のScalaコミュニティの父とも言われる方。
この方がいないとScalaはここまで日本に広まらなかったのではないかと思う。
バックグラウンドとしてはプログラミング言語学者色が強く、よく言語の構造や思想についてtwitterでつぶやかれている。
ブログはScalaのみならずプログラミング言語というものに対する深い知識が得られるので非常に有用。
吉田さん
Scalaの実践力ではおそらく日本どころか世界でも最強レベル。
Scalaの有名OSSのコミッターを見るとだいたいこの方がいて、すげえなぁという感じである。
Scala本体に加えて数々のライブラリのコミット権限を持つ。
一昔前まではScalaの関数型ライブラリのデファクトであったScalazはこの方が今はメインでメンテしている。
2019年にはPhil Bagwell AwardというScalaコミュニティの貢献者に送られる賞を受賞している。(参考)
OEさん
Scala Matsuriの主催者。
テックが強いのはもちろん、イベントなどコミュニティの運営に非常に尽力している。
この方の存在は日本のScalaコミュニティにとって非常に大きいのではないかと思う。
がくぞさん
Scalaの実装において非常に有用かつ、なかなか他では落ちていない情報を発信してくれる方。
TwitterでScalaで困ったことをつぶやくとよくリプで解決策を教えてくれる。
Twitterのフォローをおすすめする。
yokotaさん
Scala制作会社のlightbendで働いていた(今も?)。
ビルドツールであるsbtのメンテナであり、ブログではsbtの詳細な挙動についてよく書かれている。
また関数型ライブラリのcatsやscalazについての解説シリーズも書かれているので関数型入門に非常に有用。
かとじゅんさん
Chatworkのテックリード。
アーキテクチャ周りの発信が強く、DDDやCQRSで困ったらブログを読んだり質問箱に質問を投げると答えてくれる。
特にDDDは常に疑問と議論がつきまとうトピックであり、ブログはその指針として非常に有用。
言語の特徴・学べること
OOP×FP
Scalaは標榜している通りOOPとFPを生かした言語である。
始める前はだからなんだという感じだったが、今になってよく考えてみるとこれはとんでもないことである。
JavaレベルのOOPかつHaskellレベルの関数型を一つの言語でできるといえばそのヤバさが伝わるのではないだろうか。
OOPとFPの組み合わせに注目が行きがちだが、手続き的にも非常に書きやすい言語である。
特にあらゆる場面で必要以上にOOPを強制してくるJavaに比べて、Scalaはそこの強制力は弱くスクリプトチックに書くことも可能である。
次のScalaのメジャーバージョンであるScala3(dotty)では更に手続き的に書くことも可能になっている。
OOP、FP、手続き型を使い分けだが以下のセッションがよくまとまっているのでおすすめである。
Functional Object-Oriented Imperative Scala / 関数型オブジェクト指向命令型 Scala by Sébastien Doeraene - YouTube
FP
FPはScalaの大きな特徴の一つであり、Scalaを強力な言語たらしめている。
正直前はmapメソッドとか便利だよね程度の認識だったが、今は関数型が提供してくれる様々な概念なしではデイリーコーディングが冗長になりすぎてやってられない。
関数型というのは本当に強力で、複雑な問題を分割して問題をシンプルにしてくれる。
これは決まりきったような文言だけど、まさにそのとおりなのだ。
関数型的なテクニックはたくさんあるが、結局やりたいのは問題の分割で、最も重要なのはテクニックよりその思想だと言っていい。
Scalaで有名な機能といえばHaskell由来の型クラスだが、これは継承ベースの多態性に比べて変更に対してよりオープンな実装をすることができる。
特に型クラスの自動導出という機能は本当に強力で、様々な型に対して定義したものから新たに型クラスが勝手に導出される。
Scalaで有名な関数型のライブラリはcatsだけど、それ以外にも有用な関数型のライブラリはたくさんある。
それぞれのライブラリが各々の課題意識を持って見事に理論上の概念を実践に応用している。
Scalaでは常に新たな関数型の概念を実践の落とし込もうという取り組みが行われており、関数型に興味がある人は常に学び続けることのできる土壌が整っている。
型システム
Scalaの型システムはメインはjavaと同じようにnominal typeという命名を重要視する方式をとっているが、structural typeなど他の型システムの概念も取り入れている。
その型システムは他の言語でも類を見ない程に柔軟で、型システムがそれ自身としてチューリング完全になっていることも有名である。
つまり型それ自身として計算を行うこともできる。
型の抽象度という部分に注目したとき、Scalaの型の抽象度は群を抜いている。
他の大体の言語ではジェネリクス止まりだが、Scalaでは更に抽象度を上げることもできる。
ジェネリクスは型を受け取って型を生み出す型だとみなすことができるが、通常そのような型を更に抽象的に表記する方法はない。
つまりList[_]
という表記は他の言語でもできるが、このList
部分を抽象化するような型を定義することはほとんどの言語ではできない。
何を言っているかわからないと思うが、気になった方はこの記事でも読んでほしい。
まあ普段使いには最低限ジェネリクス、型の境界、変位くらいまで理解すればいいと思われる。
これらくらいならばjavaやTypeScriptユーザならほとんどの場合達成しているであろう。
javaとの違い
基本的にjavaの課題である部分を解決している言語であるため、相当に書きやすい。
またjavaベースとはいえ、基本的にjavaと同じ部分を探すほうが難しい気がする。
Javaとは違うとはいえ、javaの遺産は利用することができるためいいとこ取りである。
書き味
Scalaは本当に柔軟な言語でありいろんな書き方ができる。
手続き的にmutableなデータ構造を使ったプログラミングもできるし、もちろんこれにOOPを組み合わせることもできる。
だが一般に好まれるのは関数型指向のimmutableなプログラミングスタイルであり、これにOOPを組み合わせたものは本当に気持ちがいいし、安全である。
OOPによって人間の考え方でデータを見ることができ、関数型がそれらのデータの流れを制御する。
また関数型の力によって責任と関心事は分割される。
やろうと思えば、どこまでも純粋でどこまでも人間にとって読みやすい自然言語レベルのコードが書ける。
本当に人間的な思考でプログラミングをすることができる言語だと思う。
DDDとの相性
Scalaと一緒によく上がる話題にDDDがある。
ScalaはDDDと相性が良いのだ。
DDDはアーキテクチャ、開発体制、組織論の総称的なトピックだと思っているが、重要なのはなるべくビジネスドメインと同じ概念、言葉でコーディングするということだ。
殆どの言語ではこの目標の達成は難しい、なぜならコードというのはあくまでもコードであり、どうしてもプログラミング的な関心事がコード上に入り込んでしまう。
しかし上に述べたように、Scalaというのはほとんど自然言語と変わらないレベルのコードが書ける。
しかもどこまでも純粋関数的に。
これははっきり言って驚異的なことである。
Scala導入で大変だったこと
情報の少なさ
Scalaは基本的に導入は他のメジャーな言語よりは大変である。
大きな理由の一つは日本語での情報の少なさである。
これは情報がないというわけではなく、他のメジャーな言語に比べては少ないというだけだ。
落ちているものは落ちているし、英語の情報収集に慣れていればぐっと情報源が広まる。
ただ、やはりもうちょっと日本語アクセスできる情報源が増えれば、というのが正直な感想である。
困ったら英語文献、もしくはソースコードに当たるのが良い。
Scalaのソースコードは幸運にも非常に読みやすい。
DDD
これはScala本体の難しさかといえば怪しいのだが、Scalaでバックエンドを書くときはDDDと組み合わせるのが最近の流行りであるので書いておく。
DDDは開発に関するプラクティスが詰まった開発体制・実装パターンの総称である。
パターンなので一般的な内容についてはベスプラはそこそこ落ちてはいるのだが、もちろんそれだけでは実際の開発はカバーできない。
あくまでも自分たちの組織、プロダクトにあった正解をその都度探していく必要がある。
こういうどこにも落ちていない答えを探す作業というのは非常に大変なことである。
正解だと思ったことがあとで間違っていたなんてことはいくらでもある。
しかしだからこそ自分たちの理想をどこまでも追求できるという意味で面白くもある。
Scala以前にやっているといい技術
Scalaの導入自体は大変だが、事前に知っておくことでScalaになれることを助けることができる知識もあると思う。
1つは型あり言語の経験だ。
特にジェネリクスなどの型を多少抽象化したような概念には慣れ親しんでおくことが望ましい。
これはJavaでも良いし、最近だとTypeScriptは結構イケてるのでおすすめである。
2つ目は基本的な関数型への知識だ。
ここで言う関数型とは関数自体を値とみなしてプログラムを組み立てて行くようなスタイルのことを指す。
つまりmapメソッドのような高階関数を用いたメソッドや、その挙動を詳細に理解するためにできれば高階関数を自分で組み立てられられると良い。
カリー化くらいまでわかっていれば十分であると思う。
3つ目は継承ベースではないmixinベースの機能の合成を用いる経験である。
Scalaではtraitというjavaでいうinterface的なものがいるが、これを複数組み合わせて機能を実現していくのがよくあるプログラミングスタイルである。
普通のクラスの継承にしかなれていないとここに戸惑う可能性がある。
これは有名どころだとRubyのmoduleやpythonのmixin指向の多重継承、あとはそれこそjavaのinterfaceでもいい。
これらに加えてもちろんOOPの基本的な部分はあったほうが良いと思う。
またHaskellのような本格的な関数型の知識もあったほうが良いといえば良いが必須ではない。
それらはScalaでも後の方になって理解すればいい。
定性的な影響
議論ベースの組織
Scalaとは何度も言っているように非常に柔軟な言語で、いろんな書き方をすることができる。
ということは様々な選択肢がある中で自分たちにとっての最善を見つけ出していく必要がある。
これは誰かの独断によって成すというよりも、チーム内での議論が必須になっていく。
どんな細かい部分でも議論、つまり改善の余地があるのだ。
このような組織の性質は伝播するものであり、組織全体として議論ベースの運用になっていく。
誰かが課題を発見すればそれに対して組織・チームとして議論し、自分たちにとっての理想・最善を求めるという習慣ができる。
組織としてはこれほどに強い特徴はないと思う。
これはこの記事の内容にあるように相当昔から言われていることではある。
もちろんこれは元々議論ベースなカルチャーだったからこそScalaがマッチしたということも考えられる。
しかしカルチャーとツールが相補的になっていることは確かである。
また言語それだけで見たとき、議論を少なくする方向で設計されたGoのような言語もある。
どちらがbetterだとは言うつもりはなく、あくまでもScalaを使うことによるメリットの一つというだけである。
エンジニアの成長意欲・モチベーション
何回もいうがScalaは本当に柔軟な書き方ができる。
関数型はどこまでも読みやすく、パフォーマンス高く実装することができる。
エンジニアが望めば限界はほとんどないと言っていい言語だ。(もちろんRust、C++などには直列パフォーマンスの点では劣るが)
かと言ってなんの代償もなく何かが得られるということはなく、トレードオフの関係は常につきまとう。
Scalaを最大限有効活用する大きな代償のうちの一つは何かというと、エンジニアの能力と言っても良い。
確かにScalaのプラクティス、特に関数型は深淵で、理解するのにはコストが必要である。
これは逆に言えばエンジニア自身の能力が高ければ高いほど得られるものは大きいということである。
言語の仕様が壁になってなにかが表現できないということは他の言語に比べて少ない。
新たな概念を理解すればするほど、表現できることは増えていく。
これはエンジニアの成長意欲を強く刺激する。
関数型は未だ成長途中の概念であり、今も続々と理論・実践の両面から新たな手法が生まれている。
もちろん言語レベル以外でも他のトピックでエンジニアを刺激することはできる。
必ず成長意欲のもとになる対象がScalaである必要はないし、言語以上・以下のレイヤーで新たな概念、技術が日々生まれているのが今である。
ただScalaを使うということは非常に広範なトピックをカバーできるし、投資に見合うだけのなにかを得られるのは確かである。
情報源
いくらかScalaで役に立つ情報源をあげたいと思う。
入門
実践Scala入門
少し前まではコップ本がScalaの本で真っ先に上がるものだったが、こと入門に限るならこの本はコップ本に勝ると思う。
Scalaを書き始めるのに必要十分な知識がコンパクトにまとまっている。
特に嬉しいのはOptionなどの標準ApiやScalaTestなどの外部ライブラリの本当に実践的な内容が詰まっているところだ。
Scala入門者は一読をおすすめする。
ドワンゴscala研修テキスト
Scalaの環境構築から、文法、概念まで一通りを行っている。
1から初めて中級的な内容まで踏み込んだ内容である。
Playframeworkというデファクトのwebフレームワークを用いた課題などもあり、非常に実践的。
またScalaを通じてそもそものプログラミングで大切にしたいことも同時に学べる内容になっているのは嬉しい。
コップ本
Scalaといえばこれ、という本。
Scalaという言語をまんべんなく学べる。
特に嬉しいのはScala作者のオーダスキ先生が書いていることであり、これによって単なる使い方以上のScalaの思想が存分に学べる。
言語を学ぶときにはこれが非常に重要で、なぜその言語がその設計になっているかを納得しながら学べ、実践でも重要な指針になってくる。
ボリュームはあるがScalaを書くなら一度は通読しておくべき本である。
関数型プログラミング
cats
Scalaの現状のデファクト関数型ライブラリのcatsは関数型についての非常に大きな情報源である。
ドキュメントにはどういう思想・概念を用いて関数型プログラミングを行っていくかという部分の説明が非常に手厚く、本格的な関数型の第一歩の情報源としては有用である。
また個人的にはそのコードベースもあせて見ることもおすすめしたい。
各クラス、メソッドごとにdocがかなり手厚く書かれていて、ドキュメント以上に包括的かつ詳細な情報が得られる。
何よりも内部の実装レベルで理解できるのが嬉しい。
yokotaさんの記事
上でもあげたyokotaさんは関数型ライブラリの2大巨塔であるcatsとscalazについての超大作をかきあげている。
これらは関数型の背後に存在する圏論の話題や、実装上の都合・テクニックにまで踏み込んで解説が行われている。
Catsやscalazのコードと一緒に読むとぐっと理解が深まるだろう。
Scala関数型デザイン&プログラミング
日本語で書かれた本で唯一と言っていいほどのScala×本格関数型の本。
Scalazのメンバによって書かれたということもあり信頼性は高い。
関数型の各概念についての解説が行われており、この本を読めば関数型の入門〜中級的な概念は一通り身についたと言って良いのではないだろうか。
ただし関数型は読んでわかるというよりも実践して思考の一部にするといった側面が強く、その意識は持ちたい。
この本には練習問題がたくさんついていて、それらが実践の一助になると思う。
関数型は一見なんの役に立つかわからないような概念が回り回って実装に大きな影響を与えるのだが、練習問題を解く中でその概念と実装がどうつながっているかを理解できれば勝ちである。
英語の情報
Stack Overflow
あるあるだがこれは役に立つ。
日本語版はあまり利用したことがないのでわからないが、英語版はライブラリの製作者が答えていたりする。
またそれだけで記事になるようなコメントも多い。
調べ方を覚えるのが大事。
medium
Mediumでは日本語では見つからないような情報が驚くほどたくさん落ちている。
特にライブラリの使用例や、設計パターンなどの話題の量は日本語とダンチであり、ここの記事を日々追っているだけでScalaの実践的な知識が身につく。
開発環境周り
ide
自分はintellijを使っている。
Intellijはscalaの強力なサポートを備えていて、開発も活発である。
ideとしての構文補完的な側面では一番強いのではないだろうか。(たまに予測を間違えるが)
その他の選択肢としてはmetalsというlanguageサーバーも存在していて、それをvimやvscodeと組み合わせることも容易にできる。
Metalsはossベースで開発が進んでいて、これも日々進歩している。
ただ正直scalaはコンパイル言語ということもあり、自分がなれたエディタを使うのが一番いいと思う。
ツール系
linterとしてはwartremover、scala styel、formatterとしてはscalafmt、scalafixなど複数の選択肢がある。
既存のルールがあるだけでなく自分でルールを記述することができるものもある。
他の言語でできるようなlinter、formatter機能は十分達成できるがjsでいうeslint、prettierの様にデファクトが決まっていないのが微妙に辛い。
現在のScala周りのテックスタック
最後にこの一年で使うようになったscala周りのテックスタックを整理して終わろうと思う。
web frameworkとしてはplayを使用しており、dbアクセッサはslickである。
アプリケーションの全般でcatsを用いて冗長な記述を簡潔化している。
複数モナド周りのつらみはeffで解決していて、これがあるおかげでユースケースの記述は随分とスッキリした。
決まりきった記述はshapelessで抽象化することで解決して無駄な労力は省いている。
Json周りはplay jsonを元々は使っていたが、レポジトリによってはcirceに切り替えた。
テストはscala testを用いており、一部property based testとしてscalacheckを利用している。
property based testはまだ一部なのでもっと使いたい。
もちろんその他の細かいライブラリはあるが、大体はこんな感じである。
今後はAkkaやZio系、Monocleなども使ってみたいと思っている。
最後に
今回はこの一年でScalaをやりつつ学び、感じたことをつらつらと書いた。
Scalaは言語として非常に優秀で学んでも学んでも底が知れない。
学ぶこと、理論的なことを考えることが好きな人にはとびきりの言語だ。
この一年でScalaへの乗り換えはある程度やったし、その投資に見合うものは個人的にも組織的にも大きなものが得られたと思っている。
もっと日本でScalaを使う人が増えればいいのにと思う日々である。