「わたしは」どの言語を選択するか、あるいは選択しないか
プログラミング言語の選択
プログラミング言語の選択とは常に難しさをはらんでいます。時にその難しさは最終的に「宗教」の比喩を持って(わたしはこの比喩は間違っていると思っているのですが)論争を呼ぶことさえあります。究極的には「チューリング完全であればどれ使っても最終的には一緒w」とは言ってもパラダイムの違いによる表現力の差やエラーの扱い方の違い、文法や静的解析による開発体験の差など考慮すべき点は色々あります(SKIコンビネータがチューリング完全だからってそれで複雑なソフトウェア書きたくないでしょ?)。複数人で開発となればレベル差とかビジネスモデルがどうとかいうのも考えなければいけないでしょう。
じゃあわたしがプログラミング言語を選べる立場にある時、何を理由に選択するか、もしかは選択しないか、偏見がかなり混じってしまいますが、残しておくのも悪くないかと思いました。タイトルにもある通りあくまで『「わたしは」どの言語を選択するか、あるいは選択しないか』ですから、「あなたは」あなたなりの意見を持って言語の選択にあたってください。そしてもし何かの縁で同じプロジェクトをすすめることになった場合、その時にはどの言語を使うべきか議論をしましょう😉
選択する言語
Haskell
- 複雑なドメインロジックを記述したい時
- 副作用を分離したい時
- 並行並列処理を扱いたい時
- 構文解析を行いたい時
- プログラミング言語を作りたい時
- 開発者がみんな Haskell 使えそうな時
Haskell は素敵な言語です!よくモナドや型クラス周りが難しい難しいと言われますが、冷静になってコードを動かしてみればとてもシンプルな仕組みですし、使い方を覚えるとこれほど有用な仕組みはありません。特別な構文を加えることなく並行並列、例外処理、大域変数などなどの仕組みをモナドだけで表すことができます。型レベルプログラミングなどを組み合わせると複雑なドメインロジックもきれいに切り離せて関心の分離を行うことができます。
また、Haskell は副作用をコントロールできる数少ない言語です。これによって副作用の分離が非常にしやすくなり、テスタブルなコードが書きやすくなります。というか関数書いた時点で「これ自明じゃね」か「これ I/O 挟むからユニットテストじゃなくね」になりがち。
Rust
- 堅牢で高速なソフトウェアを作りたい時
- WebAssembly を吐きたい時
- 低レイヤーをいじりたい時
- クロスビルドしたい時
何かと話題に上がる Rust ですが、こちらの魅力はなんと言っても実行速度と安全性です。実行速度は C にはかないませんが、安全性は抜きん出ているでしょう。型レベルでの安全性に加えムーブセマンティクスを用いたメモリ安全性は他では得られないでしょう。
加えて実行速度が高速でありながら、列挙型とパターンマッチ、ジェネリクスやトレイトを用いたそこそこ抽象度の高いコードを書けることも魅力的です。
クロスビルド環境も整っているのも使いでのあるところです。Arm 向けバイナリなんかを x64 から吐けるのでラズパイ用のソフトとかでも使えますね。組み込みでも使ってるところがあるとか。
Go
- 型がほしいけど疲弊したくない時
- 開発体験の良さを求める時
- 複数人で開発する時
- マイクロサービスを作る時
ジェネリクスがなくて苦労する Go ですが、大体の場合あったほうが苦労したりするものです。コンパイル時間遅くなるし。それにエディタの補完を含めた開発体験が非常によろしいので書いててストレス少ないのがよいですね。コンパイラのエラーが不親切だったりポインタ関連で安全じゃなかったりするので実はそのへん玄人向けだと思うんですが、どうなんでしょ。
マイクロサービスは、実は開発に携わったことないので霊感での話になるんですが、1 サーバーあたりの責任も小さくなるのでソフトウェアも単純になり型システムも Go くらいで十分、そんなふうに予想してます。いやほんまかどうか知らんけど。でもクリティカルな部分だけ型の強い言語を使いそれ以外は Go で楽する、というのはよさそうに見えます。
TypeScript
- Web フロントエンドを開発する時
事実上一択と言ってもよいでしょう。型システムは複雑だし JavaScript との互換性を取って面倒なことになったりしてる部分もありますが、それでもないよりはマシです。バックエンドをこれで書くのは懐疑的ではあるんですが、SSR とかある以上もうちょっと考え改めないかんなと最近思ってるところ。
C
- とにかく速度を追求したい時
- メモリをガリガリいじりたい時
- アルゴリズムを再実装して理解するため
- 組み込み開発
C はプログラマーにおける古典として一度は通っておいたほうがよいと思うんですけど、いかがでしょう。コンピューターの動作の理解にはこれがよいと今でも思ってます(なにか良い代替案があったら教えて下さい!)。実際の用途としては画像処理みたいにメモリ直接いじりたいときとか、組み込みで C かアセンブリしか使えないって時に使うくらいですね。
C++
- テンプレート使ってヤバいことしたい時
もう久しく触ってないので選択するか微妙なんですが、上記のようなことをやってみたくなったら使うでしょう。せっかくなので最新の C++ にキャッチアップしておきたいという気持ちも。
選択しない言語
物事は「選択するもの」より「選択しないもの」の方が重要であると誰かが言っていたような。
Ruby
- 記述が自由で読みにくい
- 「規約」を守るコストを支払う必要がある
- まつもとゆきひろ氏のコメント読むと型推論エアプなのでは
- ローカル環境構築面倒そう(そこまでは使い込んだことがない)
- タプルがない
- Hash のキーに Array (という名のリスト)が使える
- mutable なものが hashable やったらあかんやろがい
-
Ruby on Rails を使うな
- Active Record 使いたいだけでしょ
- と思ったら他にまともそうな ORM がなさそうだった……
- Active Record 使いたいだけでしょ
……ちょっと怨念じみた書き方になってしまいましたが、冷静になって考えてみても選びたくない言語の一つです。やはり「記述に自由がある」というのは「読みにくいコードが書けてしまう」ことの裏返しなのです。きれいなコードを書くために「規約」を優先させるのは割と人にパワーを要求します。だったら仕様に取り入れて機械的に弾いたほうがいいでしょ、というのがわたしのスタンスです。型についても同様で「型を書かなければいけない」のではなく、「型を書いておくことで機械がダメなコードを弾いてくれる」が実態なので、トップがそれを理解していなさそう(していたら大変申し訳無い)なのはスタンス違いです。
JavaScript
JavaScript は機械の生成する中間言語なので人間が読み書きするためのものではないです。
Haskell
- ビルドが遅い
- 開発体験あまりよくない
- 最近は改善されたという話も聞く
- ちょいちょい使ってはいけない関数とかパフォーマンス周りに罠がある
- ええ……周りの開発者に Haskell 教えてくの……?
- GHC のダウンロードが遅い!!!
いい言語!いい言語なんですが……実際にプロダクトで使うかって言うとなかなか縦に振りにくいよねと言うのは実情。型のおかげでエラーが少ない言うけど結構落ちとるし。あとビルドがかなり遅い。手元でビルドが遅いのはコーヒーでも飲んでれば済む話なんでいいんですが、CI でビルド遅いのは CI 落ちたりして厄介。キャッシュとか面倒。そしてキャッシュしても遅い……。
Java/Scala/Kotlin
この辺はあえて選択しないというよりは触ったことがないからというのも大きいかも。だって JVM の管理面倒そうなんだもん……。
PHP
ごめんなさい、<?php
でコード始まるのがやっぱ無理でした。
Elm
- すごくシンプルに纏まっていて良い言語
- 純粋関数型だし型も複雑でないので関数型を学ぶのにうってつけ
- コンパイル後のコードも小さい
- TEA(The Elm Architecture)で UI の動作を記述すると見通しが良くなる
- コンパイラがめっちゃ親切
褒めてばっかじゃん!なんで選択しないに入れたの?って感じですが以下がその理由になります。
- Elm で提供されてない機能を使おうとすると途端に面倒くさくなる
- コンポーネントという概念がないので分割・再利用がしにくい
- npm のエコシステムに乗っかれない
- 副作用の発行に厳しい
- GUI は副作用の塊みたいなものなのでこれは結構きつい
全体的な評価としては「すごく綺麗にまとまっていて使いやすいんだけどこれで Web の動作を記述するには馬力不足」といった感じ。ちょっとまだ最前線では使えませんな……。良い言語なんですけどね、だがしかし。
選択の基準
色々と書きましたが、最後に選択の基準でも書いて終わりにしようかと思います!
- 型推論のある静的型付け言語であるか
- チームメンバーがプログラミングにどれだけ習熟しているか
- 目的に対して複雑すぎる型システムでないか
- 開発体験とのトレードオフ
まー最終的に選ぶ立場になったら「これ使いたいから使ってみっか」になるんですけどね!!
Discussion