背景
最近、プロジェクトのアプリケーション開発で選択する言語で迷う事が多い。
今一度なぜGoでアプリケーションを書くべきなのかをアーキテクトな視点でまとめてみる。
特に、既存あるいは新規プロジェクトで、サーバアプリケーションをjavaで開発すべきかGoで開発すべきか、という議論から始まる事が多い。
特にサーバサイドをコンテナ化していく、という際にAPI用プログラムにGoを選択する。
JavaではなくGoを選択する理由とは何なのか。
なぜ、「ナウいGo使おうぜ」では満足しないのか
もちろん、新しい技術を採用し知見を溜めたい。
今後の潮流にのっかるために、目の前のプロジェクトをお試しとしてGoを選択する、という案もある。
一方で、既に技術者や知見が残っている、安全性の高い言語で目の前のプロジェクトを安全に終わらせたい、という人間も少なからずいる。
そういった人間を説得しなければならず、そういった人たちには「新しいこと」は害悪である。
彼らは分からないことが怖い。新しい技術だからこそ、採用を見送りたく思うのである。
だから、新しい言語を選択したときに考慮しなければならない点、デメリットについて考えなければならない。
今回はマネジメント視点は除外し、サーバアプリケーションを開発する、という視点でのメリットとデメリットを考えてみた。
Goのメリット
- コンテナの起動速度が非常に速い。耐障害性を考えた際に~分で新しいコンテナが起動するJavaと、秒で新しいコンテナが起動するGoではやはり後者にメリットを感じる。
-
javaであるgcがないこと。Javaと比べてGCによるオーバーヘッドが小さいこと。オンラインシステムでGcにこれまでやられて来たよね。
Goのデメリット
- オブジェクト指向ではないこと。
ここで、「オブジェクト指向でないこと=デメリット」と考える具体的な理由は何なのか?
なぜオブジェクト指向だったのか
C言語だった我々があるときjavaを手に入れた。その時にそもそもCで感じていた課題感とJavaのメリットは何だったのか。ドンピシャの本があったので読了
『オブジェクト指向でなぜつくるのか』 (平澤 章/日経BP)
以下、上記の本の要旨。
C言語からJavaに世界が流れた理由
Step1. 機械語からアセンブリ言語
- 機械言語は人間には理解しにくい。人間で理解できる言葉で書けるようアセンブリ言語が生まれた。アセンブリ言語からコンパイルにより機械語に変換するようになった。
Step2. アセンブリ言語から高級言語
- メモリ上などのコピー処理の手順を記載する必要があるなど、アセンブリではまだ記載が複雑だった。そのため、更に高級な言語が作られた。
- Cobolは申請書のようなフォーマットで書くことを目指して。
Step3. 構造化プログラミング
ポイントは以下2点
- 更に分かりやすく作成するために考案された。
- GOTO死すべし
プロジェクトを分かりにくくしている元凶であるGOTO分を廃止。ロジックを逐次進行、条件分岐、繰り返しの3つのみで表現することを提唱した。そもそも、それまではプログラムが小さくメモリを利用しないことが必要とされていた。そのため、分かりやすさよりトリッキーなコードだった。 分かりやすさを考えた場合、GOTOは廃止したほうが良い。
保守性の高いサブルーチンの考え方
サブルーチンの独立性を高めて保守性を高める必要がある。
重要なのは、サブルーチンの独立性を高める方法は呼び出し側とサブルーチンで共有する情報を少なくしたい。ただし、共有する情報をグローバル変数とし、全体から参照されてしまうことでグローバル変数の書き換えについて書き換え元を特定できず、デバッグに時間がかかる。そのため、外部から参照されないローカル変数が発明されし、値渡しを前提とした。これで、サブルーチンが勝手に他のサブルーチンが参照している値の書き換えをしないようになった。
ここで残った問題点
-
グローバル変数問題:長期的に必要な値はプログラムを書くために必要。ただし、ローカル変数は関数消えたら消えてしまう。結局グローバル変数は残る。そのため、グローバル変数をどこから参照しているか、影響範囲を調べるためにロジックをすべて調べなければならない。
-
貧弱な再利用:サブルーチン程度しか再利用されない。より大規模な再利用が必要。
Step4. オブジェクト指向
外部から参照される変数、手続きをクラス化してまとめた。
クラスの効用-まとめる、隠す、たくさん作る。これにより、大規模な再利用ができるようになった。
そして、Goを選択する理由とは?
このオブジェクト指向の流れを踏まえたうえで、言語選択について考えなければならない。
結果、Goのオブジェクト指向でないことがデメリットとなるのは、条件がある。
- 外部から参照される変数、手続きをクラス化してまとめる必要があること
- フレームワーク化してより大規模な再利用が必要となること。
この2つが必要となるとき、Javaが力を持つ。
しかし、「サーバサイドをコンテナ化していく、中で、サーバサイドのAPI用プログラムにGoを選択する」という場合はどうだろうか?
上記を考えた時、APIを設計する、という行為の中に上記オブジェクト指向で対応した問題点が内包されている。
APIのRestの考え方
APIではRESTFulという考え方がある。
詳細は割愛するが、RESTFulAPIでは機能を(ドメイン指向などありますが)最小単位とし、CRUDをHTTPのプロトコルで表現する
APIを設計する。これががそもそもオブジェクト指向におけるクラスの作成に似ている。
APIのバックエンドにデータベースを持つことにより、長期的なデータの保存が可能となる。
APIのインターフェースを設計することにより、外部からなんの情報が参照され、更新されるかが明確になる。
tokenのscopeにより制御範囲を明確にすることにより、誰に何を提供しているかが明確に判断できる。
グローバル変数変更する際、影響範囲を調べるためにロジックを全て調べなければならない、問題はAPIのインターフェースを変える際にv1/v2とバージョンアップすることにより、
古いインターフェースを守りながら、新しいインターフェースを提供することができる。
結論
つまり、APIの設計をする、ということがオブジェクト指向における隠ぺい化を担っている。
APIの設計をするということが、オブジェクト指向のクラスを分類する、という行為と似ているのだ。
その前提をもって、設計されたAPIの実現であれば、Goによる開発のメリットを受けられるのではないか。
マイクロサービスアーキテクチャ、を実現するためにAPIを実現するときに、軽量かつ高速なGoという言語がその真価を発揮する。メリットを享受し、デメリットをより上位の設計で吸収することができる。
と、考えてサーバAPIの実装はGoに限ると思っています。