こんにちは、Misoca開発チームの黒曜(@kokuyouwind)です。
そしてこの記事は弥生 Advent Calendar 2020の 11日目の記事です。
昨日の担当はkosappiさんのCodePipelineのステージ間で変数を受け渡しするでした。
プログラミング言語について
Misoca開発チームでは主にサーバーサイド側言語としてRuby、クライアントサイド言語としてTypeScriptを利用しています。
一方で弥生製品開発チームは主にC#を利用しており、最近ではTypeScriptやGo言語も一部で利用しています。
そうなってくると、気になるのは「今後新しいプロダクトを作るとしたら、プログラミング言語は何にするべきなのか?」ということです。
今回はそれぞれの言語の特徴や向いている用途について、ざっくりまとめていきたいと思います。なお極力資料を探しながら正確に書こうと思いますが、個人的な印象やイメージが入ってしまう部分もあるかと思いますのでご了承ください。
なお誕生時期や特徴の主な出典はプログラミング言語図鑑に拠ります。
- 作者:増井敏克
- 発売日: 2018/04/13
- メディア: Kindle版
目次
Ruby
言語の特徴
Misoca開発チームがバックエンド開発に使っている言語です。日本発で個人開発から始まったという、割とレアな出自を持っています。また公開が1995年と、実はC#より長い歴史を持つ言語です。
Rubyの特徴として、C++に代表されるクラスベースのオブジェクト指向よりも、Smalltalkに代表されるメッセージベースのオブジェクト指向を強く意識していることが挙げられます。
多くの言語では、数やそれ以外のプリミティブな型はオブジェクトではありません。 ですが、RubyはSmalltalkの影響を受け、すべての型がメソッドやインスタンス変数を与えられるようになっています。 これがRubyが使いやすい理由の一つです。 Ruby公式ページ - Rubyとは より
この特徴と、メッセージ呼び出しやブロック渡しでの柔軟な構文によって、Rubyでは自由度の高い言語内DSLを定義することができます。
例えばRailsの routes.rb
ファイルは以下のように書くことができますが、これは妥当なRubyコードになっています。*1
Rails.application.routes.draw do resources :brands, only: [:index, :show] do resources :products, only: [:index, :show] end resource :basket, only: [:show, :update, :destroy] resolve("Basket") { route_for(:basket) } end
他にも関数型プログラミングの要素が取り入れられていたり、オープンクラスとオーバーライドによる柔軟なクラス拡張が行えたりなど、とにかく「プログラマが自然に書きやすい」ことを重視したまつもとひろゆき氏の思想が伺えます。
向いている用途
最も普及している用途はRuby on RailsによるWebプログラミングで、特にスタートアップなどの小規模かつ迅速な開発で強みを発揮します。
他に言語内DSLの特性を活かしてVagrantやChefなどの設定ファイルでの利用が有名です。またサーバ内で実行するバッチ処理などのスクリプト用途でも手軽に書きやすく重宝します。
一方で、自由度や動的な型システムによって大規模開発では混乱を生みやすい言語だといえるでしょう。また実行速度の面では遅い部類に入るため、処理速度が重要な場合はあまり向いていないと言えます。
なお12月25日(クリスマス!)にリリースされる予定のRuby 3.0*2では静的型検査システムの導入や実行速度の改善などが行われているため、これらの懸念点が多少緩和されるのではないかと期待しています。
C#
言語の特徴
弥生製品チームが主に利用している言語です。マイクロソフトが2000年に公開した、汎用目的のオブジェクト指向言語になっています。
一般に使われ始めたのは、Visual Studio .NETに組み込まれた2002年からになりそうです。それまでのネイティブビルドがターゲットだったVisual Studioシリーズ(6.0まで)から、.NET FrameworkをターゲットとしたVisual Studio .NETに移行するタイミングで追加されただけあり、.NET Frameworkの標準的な言語という扱いを受けています。*3
C++の構文をベースにしつつも、低レベルのメモリアクセスは基本的に制限したりガベージコレクションが標準で利用されるなど、自分の足を撃ち抜くことがないようになっています。型システムは.NETの共通型システムに依りますが、おおむねclassやinterfaceを用いたクラスベースのオブジェクト指向といえるでしょう。
またC# 3.0で追加されたLINQ用のクエリ式やC# 7.0で追加された関数型プログラミング由来のパターンマッチ機能など、積極的に様々な機能が導入されています。
特にクエリ式によって、データベースに対するクエリ発行を以下のように言語内で記述できる点は特筆すべきでしょう。*4
IEnumerable<string> highScoresQuery2 = from score in scores where score > 80 orderby score descending select $"The score is {score}";
ほぼSQLと同じ内容を言語内で記述できるため、構文検査や静的な型検査もコンパイル時に行えるのは強みといえます。*5
向いている用途
.NET Frameworkの主力言語であるため、Windowsデスクトップ開発においては最有力候補と言えます。またUnityでのスクリプティングにおいてもC#が採用されています。
.NET ASPなどを利用したWebプログラミングも可能で、大企業やSIerなどの大規模プロジェクトで利用されているように思います。
一方で、やや文法が古くボイラープレートコードが多くなること・開発環境が実質的にVisual Studioに制限され自由度が少ないこと・稼働環境にWindowsサーバライセンスが必要になることなど諸々の問題から、スタートアップなど小規模なWebアプリケーションでの採用は稀という印象です。
またWindowsや.NET Framework自体が重厚なため、昨今のコンテナ化・マイクロサービス化の文脈ではコンテナサイズやメモリ使用量が膨らみやすいという点で他言語に軍配が上がりやすいと言えるでしょう。
こうした状況はMicrosoftも把握しているようで、.NET Coreのマルチプラットフォーム対応や.NET 5での単一の実行可能バイナリ生成など、着々と改善を重ねています。BlazorによるWebAssemblyアプリ作成などもあり、今後の展開によっては小規模Webサービスやマイクロサービス用途でも選択肢に挙がってくるかもしれません。
Go
言語の特徴
弥生基盤チームが一部で利用している言語です。Googleが2009年に公開した汎用目的のプログラミング言語です。
Goの基本的な言語仕様は単純で、個人的にはBetter Cという印象を受けます。ただしinterfaceを利用したオブジェクト指向機能と、GoRoutineを用いた並列処理機構の2つは非常に特徴的です。
Goのオブジェクト指向ではクラス定義を行うことはできず、どんなメソッドを持つかのinterfaceのみを定義することができます。そしてある型がinterfaceのメソッドを全て定義していれば、その型はinterfaceを実装しているとみなされます。
例えば、sort.Interfaceは Len() int
, Less(i, j int) bool
, Swap(i, j int)
の3つのメソッドを要求するため、これらを定義した型であればsort.Sortに渡して整列することができます。いわゆる構造的部分型ですね。Rubyでよく言われるダックタイピングのような振る舞いを記述できますが、コンパイル時にインターフェイスを満たしているか静的に検査できる点が優れています。
GoRoutineはマイクロスレッドを立ち上げるための言語機構です。Erlangのマイクロスレッドに近いですが、各プロセスがメッセージボックスを持つアクターモデルではなく、チャネルを通じて同期的に通信を行うCSPスタイルとなっています。
また標準でコードフォーマッターや単体テストライブラリなど組み込みのエコシステムが整備されており、コンパイルすると単一実行ファイルが生成されるため、コンテナベースのCI/CDといったモダンな開発プロセスに適応しやすくなっています。
向いている用途
Googleが自社向けに設計しただけあって、コンテナを利用したマイクロサービスシステムでは最初に名前が挙がる言語でしょう。ユーザが直接触れるWebアプリよりも、マイクロサービス内部のAPIサービスで特に強みを発揮するイメージです。また静的型システムを持ち並列処理機構も言語標準で持つため、Dockerなどミドルウェアの開発でも積極的に採用されています。
一般的なWebアプリでの利用も十分可能だと思いますが、Webフレームワークはデファクトが固まっておらず、フロントエンドも通してカバーできるTypeScriptに軍配が挙がっている印象です。もっとも、標準ライブラリのみで簡単なWebアプリなら作成できてしまうため、Webフレームワークの必要性が低いという事情もありそうです。
TypeScript
言語の特徴
Misoca開発チームがフロントエンド開発で利用している言語です。また弥生製品チームでも一部で利用されています。マイクロソフトが2012年に公開した、いわゆるAltJS言語の一種です。
JavaScriptに型検査システムやスコープ制限などの機能を追加した言語で、JavaScirptの厳密なスーパーセットになっているため既存のJavaScriptソースをそのまま利用でき移行が容易という点で他のAltJS言語と一線を画しています。
また型システムも非常に特徴的で、典型的なプリミティブ型・オブジェクト型などに留まらず、リテラルの値に依存するリテラル型や型レベル関数など意欲的な仕様が取り入れられています。
例えば、以下のように方位を表す "North"
, "East"
, "South"
, "West"
のいずれかのみを取る型 CardinalDirection
を定義することで、 move
にそれ以外の文字列が渡されないことを型レベルで保証できます。*6
type CardinalDirection = | "North" | "East" | "South" | "West"; function move(distance: number, direction: CardinalDirection) { // ... } move(1,"North"); // Okay move(1,"Nurth"); // Error!
一方で、型注釈を間違うと容易に型の整合性を崩せるなど健全性は諦めている部分があり、型検査を実用的なレベルで妥協するという割り切りが感じられる言語です。
向いている用途
現状のフロントエンド開発ではデファクトスタンダードと言えるでしょう。またサーバーサイドJavaScriptエンジンであるNode.jsを組み合わせることでサーバサイド開発でも利用することができます。
特にフロントエンド・サーバサイドを跨いだJavaScriptフレームワークであるNext.jsやNuxt.jsなどは迅速な開発が必要なスタートアップなどで非常に人気があり、TypeScriptと組み合わせて採用するケースが増えているように思います。
静的型検査があるため開発規模が大きくなってもある程度はスケールしますが、コンパイルターゲットがJavaScriptであり速度面では他言語に劣ること、標準で利用されるnode_modulesが肥大化しやすくコンテナイメージが膨らみやすいことなどから、大規模開発では他の言語に分があるといえそうです。
とはいえTypeScript界隈はコミュニティが非常に活発であり、新たなツールでこうした課題が改善されていく可能性は十分ありそうに思えます。
その他の言語
他に、個人的に最近使われていると感じたり気になっている言語は以下のとおりです。
- Swift : iOS開発開発のデファクトスタンダード。サーバーサイドSwiftという選択肢もあるが、事例は少なそうに感じる
- Kotlin : Androidアプリ開発のデファクトスタンダード。サーバーサイドKotlinという選択肢もあるが、やはり事例は少なそうに感じる
- Scala : オブジェクト指向と関数型プログラミングをいい感じに組み合わせたJVM言語。書ける人が書くと非常に生産性が高いが、設計方針が統一されていないとパラダイムが混ざってカオスになる。あとimplicit parameterを多様するとコンパイルがどんどん重くなる
- Rust : 所有権管理が厳格なため、低レイヤー処理を安全に記述できる言語。ミドルウェアやドライバーなどハードウェア寄りのソフトウェアで特に強みを発揮するイメージ
- F# : .NETに対応した関数型言語で、OCamlの文法をベースにしている。型プロバイダなど表現力が高いが、Scala以上に関数型寄りのパラダイムを持つためOCaml・Haskell辺りの経験がないと学習コストが高い
まとめ
いろいろなプログラミング言語がありますが、それぞれに設計者の思想や目的がある以上、用途に合わせてプログラミング言語を選ぶことで特徴を活かして輝かせたいですね。(雑なタイトル回収)*7
弥生 Advent Calendar 2020、明日の担当はmasuda_Mtenさんです。お楽しみに!
*1:routes.rbのコードはRailsガイド - Rails のルーティングから引用
*2:現時点ではRuby 3.0 preview 2がリリースされており、試すことができます。
*3:J#? 知らない子ですね…
*5:LINQやクエリ式はVB.NETやF#でも利用できるので、.NET系の言語共通の強みと言ったほうが正確かもしれません。
*6:コードはTypeScript Deep Dive 日本語版 - リテラル型から引用
*7:蛇足ですが、タイトルの元ネタは「君の青春は輝いているか」です。