ぱろっと・すたじお

技術メモなどをまったりと / my site : http://parrot-studio.com/

Goをやらないとまずいと言われたので触りつつ、適用範囲を考える

まあ、きっかけは流れてきたこれなんですが・・・

www.benfrederickson.com

・・・突っ込みどころはあるのですが、そこはおまけに回すとして、
重要なのは「Goが伸びている」ということですよね

前から一度くらいGoに触ろうとは思っていたものの、そのきっかけがなかったので、
せっかくなのでGoを軽く書いてみたわけですが・・・

github.com

・・・結論からいえばRailsっぽいものをGoで書こうとするな」ってことですΣ(・ω・ノ)ノ

Goの環境構築(GOPATHの罠)

インストールはMacなら「brew install golang」とかするだけなのですが、
ややはまりどころなのが「GOPATH」の設定です

GOPATHは全てのコードが配置されるベースPATHです
それこそ、自分のコードもライブラリも関係なく「全部」です
Goのimportは全て、GOPATHからの相対PATHとして定義されています

逆に言えば、全てのGo関連のコードに同じPATHが強制されるため、
(gemやyarnのように)バージョン管理をするという概念はありません *1

# .bash_profileや.envrc等
export GOPATH="/path/to/gopath"
export PATH="$GOPATH/bin:$PATH"

こんな感じで、GOPATH/binにもPATHを通しておけば、より安心かと(`・ω・´)

Goの仕様

Amazonにちょうどいい本があったので、ポチってみましたが・・・

・・・1時間もかからずに概要は把握できますΣ(・ω・ノ)ノ

言語仕様に難しい要素はないというより、
意図的に徹底して複雑なパラダイムを排除しているくらいです

プロとして何らかの言語で実績があるプログラマはもちろん
大学で軽くCを触ったことがあるくらいでも、おそらく書けてしまいますし、
まさにそれがGoの重要な「設計思想」だと思います *2

「誰が書いても一定のクオリティのコードが強制される」という意味では、
Pythonに近い思想ですが、圧倒的に簡単です

Pythonのように言語自体がインデントを強制するのではなく、
gofmtというフォーマッタをデフォルトで持っており、
そういった意味でもPythonより柔軟で現実的な仕様だと思います(`・ω・´)

なぜGo言語 (golang) はよい言語なのか・Goでプログラムを書くべき理由


RailsっぽいものをGoで書いてみる

こうなると、何かをGoで実装してみようという話になるのですが、
チェンクロパーティーシミュレーター(以下ccpts)のAPI層をGoで書いてみることに

Get our light! - チェンクロ パーティーシミュレーター

GitHub - parrot-studio/cc-pt-viewer

  • DBの定義やデータはそのまま使用
  • APIにアクセスしたら「最新アルカナ一覧」をJSONで返す

サンプル的にまずはこれだけ...φ(・ω・`)

どんな言語でも、最近は「Railsっぽいもの」がたいていあるので、
軽く探してみたところ、こちらが見つかりました

https://revel.github.io/Railsっぽいもの)

http://doc.gorm.io/ActiveRecordっぽいもの)

後者はマイグレーションとか備えていてなかなかですが、
今回は不要なので、接続とmodel定義部分だけ使いました

package models

type Arcana struct {
	Id             uint64 `gorm:"primary_key" json:"id"`
	Name           string `sql:"size:100" json:"name"`
	Title          string `sql:"size:100" json:"title"`
	ArcanaType     string `sql:"size:20" json:"arcana_type"`
	Rarity         uint32 `json:"rarity"`
	Cost           uint32 `json:"cost"`
         // 以下略
}

こんな風に書くだけで、JSONへのシリアライズも定義できるのは楽ですね(`・ω・´) b

JSONを返すController部分も本質的にはこれだけです

func (c Api) Index() revel.Result {
	arcanas := []models.Arcana{}
	DB.Limit(20).Order("id desc").Find(&arcanas) // なんとなくActiveRecordっぽくかける
	return c.RenderJSON(arcanas) // リストを渡すだけでいい感じにJSONにしてくれる
}

あとは、revel経由でコンパイル・実行するだけで、APIが動いてしまいますΣ(・ω・ノ)ノ

$ revel run ccptsgo
# http://localhost9000/api にアクセスするとJSONが返る

コンパイルもびっくりするほど速く、「rails s」したときより速いかもしれませんΣ(゚Д゚)ガーン

こうなると、うまいこと関連のmodelとかもJSONで返せるのでは・・・と、
調べようと思ったところで、ふと思ったのです

果たしてこのままccptsをGoで実装することに意味はあるのか・・・とΣ(・ω・ノ)ノ

一本APIができたことで、全体の工程がおぼろげながら把握できるようになったわけですが、
それにより逆に「Railsが暗黙的にやっていることをRevelで実装するコスト」も見えてきまして、
その多大なコストをかけてGoで書いたところで、コストとメリットが釣り合わないよね・・・と*3

Goの使いどころ

そもそも、Goが出てきた経緯を考えれば、
Goは「大規模なコードを書くための言語」ではなく、
「大規模システムを構成する "小さなコンテナ" を書くために特化した軽量言語」なのです

GoogleMapReduceを発表してから今まで、
大規模システムは「小さな何かが協調して大きなデータを処理する」という形で進化してきました

「小さな何か」はクラスタ*4だったり軽量プロセス*5だったりしましたが、
最近だとOSとアプリが一体化した「軽量コンテナ」になっていて、
そのコンテナの上で動くバイナリを実装する言語としてGoをとらえるとしっくりきます

だからこそ、Goはクロスコンパイラを持っているのです
コンテナのOSはそれ自体が超軽量で特殊な環境であり、
プログラマが使っているOSとは全く異なるはずですからね

先日もDockerに関してちょっと書きました*6が、
マイクロアーキテクチャをベースにした時代にあわせて、
同じようにDockerという「軽量コンテナをデプロイする仕組み」ができたと考えられます

すごく極端な例で言えば、Railsアーキテクチャをこのように分割するのがコンテナです
(これが正しい設計はどうかはともかく)

# [xxx] それぞれがコンテナ
[リクエスト受け付け] IN:テキスト OUT:リクエスト情報テーブル 
-> [リクエストのparse] IN:リクエスト情報テーブル OUT:リクエスト情報(header/body/etc...)
-> [ルーティングの選択] IN:リクエスト情報 OUT:処理先コンテナ名
->[リクエストの処理] IN:リクエスト情報 OUT:レスポンス情報
  -> [パラメータのparse] IN:リクエスト情報 OUT:パラメータテーブル
  -> [model取得(検索)] IN: リクエスト情報 OUT:modelの配列
    -> [データリソースへのアクセス] IN:クエリ OUT:結果
    -> [結果をmodelに格納] IN:結果 OUT:modelの配列
 -> [結果の構築] IN:modelの配列 OUT:レスポンス情報

「一つのメソッド」が「一つのコンテナ」くらいの粒度で考えれば、
Goがシンプルな構造しか持たないとしても、なんら問題がないことがわかると思います

先ほどのサイトにもこういう問題が挙げられていましたが・・・

Go言語(Golang) はまりどころと解決策

・・・そもそも、これが問題にならない粒度の「小さなコード」に使うべきなんだろうなと

「こんな非効率なことは意味がない」と思うかもしれませんが、
MapReduceが適用されるような)大規模なデータを扱う場合においては、
モノリシックなアプリの常識は通用しません(´-ω-)

逆に言えば、Goを適用するような「軽量コンテナの集合体」の場合、
「どのようなコンテナに分割するのか?」という設計が最重要課題になります

小説ではありますが、こちらに登場する「Vilocony」と、
その上に構築された「KNGSSS」こそ、
(言語がJavaとはいえ)まさにコンテナを用いた大規模システム開発の事例と言えるでしょう

el.jibun.atmarkit.co.jp

現実でもコンテナの運用はいろいろ難しいらしく、
白川さんの能力と執念がなければカットオーバーは難しかった気はしますが、
わかりやすい事例です

そもそも、Go自体が関数型的な仕様を持っていなかったとしても、
コンテナを用いたシステムの設計そのものに関数型的な思想が必須になるわけで、
関数型的な知識がGoで構築されたシステムに適用できないなんてことはないはずなんですよね(´-ω-)

関数型的な設計でよく出てくるのがUNIXの思想で、
「小さなプログラムをつないで処理」が、「小さなコンテナをつないで処理」になっているだけです
その意味では、UNIXは立派な「マイクロアーキテクチャのシステム」です

まとめ

Goの設計思想を考えれば、「コンテナで構築された大規模システム向け」だとは思うのですが、
今までのモノリシックなシステムで適用できないのか・・・というと、
全くできないってことはないはずです

(私のような)「普通のエンジニアが考える普通のWebサービス」は、
おそらくRuby/PHP/Python等の方が実装工数が小さく、
必要なライブラリが揃っており、リリースまでの工数を小さくできると思います

そういったシステムが肥大化していって、
パフォーマンスが要求された場合に、裏側の一部をGoのコンテナに置き換えていく、
なんて改善計画は十分にありだと思います *7

幸い、Goは前述の通り「言語仕様がめっちゃシンプル」なので、
「何らかの言語を触ったことがあればとりあえず書ける」という利点があります

frasco.io

こちらの記事でも、「普通に書くだけでかなりのパフォーマンスが期待でき、
チューニングの時間を短縮できる」と書いてますが、
一方で、「CURDを扱うだけの普通のAPIPythonがいい」とも書いてあります

やはり・・・

システムをうまくレイヤー分けして、それぞれの処理が得意な処理系(言語)を選ぶ

・・・というのが大事ですね(´-ω-)



(そしてまたおまけに続く・・・)


<おまけ>

冒頭のあれについていろいろと...φ(・ω・`)

www.benfrederickson.com

私も普段はRubyを書いているので、
Rubyがdisられた(ように見える)記事にイラッとするのは当然なのですが、
できるだけ冷静に分析しますと・・・

そもそも元記事にも書いてある通り、
そもそもGitHubRubyコミュニティから広まったのを考慮すれば、
Rubyの "割合" が急落している」のは当然です(´-ω-)

そもそも、海外ではPythonが優勢ってのは、
Railsが出始めた頃からずっと変わらない*8わけで、
Rubyのコミュニティが一定ラインから増えないというのもわかります

一方で、私の前に "プロのWebエンジニア" 志望者がいたとして、
「"プロとして稼ぐ" ために今学ぶべき言語」を私が勧めるとすれば、
やはりJavaScriptPHP(可能ならその両方の組み合わせ)だと思いますΣ(・ω・ノ)ノ

なにしろ案件の数が違いすぎます
Rubyは自社サービスとか一部の受託がメインですが、
PHPは大小さまざまな仕事が存在し、WordPress界隈も含めて考えれば圧倒的に多いです

さらに、昔と違ってサーバサイドはAPIに特化し、
フロント側に制御ロジックが移っている現状において、
JavaScriptに詳しくて損をすることは絶対にありません

もっとも、「JavaScript」を「jQueryの実装言語」と見るか、
「React(や最近のフロントフレームワーク)の実装言語」と見なすかで、
だいぶ見ている世界が違うので、そこは注意がいります(´-ω-) *9

"Web" というより "アプリまで含めたWeb全般" まで視野に入れているのであれば、
アプリの実装言語として(流行は押さえつつも)個人的には「C#」をお勧めします

「一番稼げるアプリ」は言うまでもなく「ゲーム」ですが、
ゲームアプリであれば圧倒的にUnityであり、
UnityをガチでいじるのであればどうしてもC#が有利になってきます
(Unityは他の言語でも書けますが、元々CとかC++を使っていた領域なので、自然とC#に収束します)

どんなに技術を磨いても、給料を上げたければ「儲かっている会社」に行くしかなく、
それはもう圧倒的にゲーム関連ですからね・・・(´-ω-)

ゲーム会社に興味がなかったとしても、Unityのおかげで
「一つのツールでAndroid/iOS両対応できる」ことの利便性が広がっており、
今後Xamarinが伸びてくる可能性も十分にあると思ってます *10
(特に日本国内だと、iOSのシェアが大きすぎて、Androidだけに特化するというのも難しいですし)

・・・と、距離を置いて書いたものの、日本国内でいえば圧倒的にRubyが強いのも事実です
Rubyで書かれた有名Webサービスは多数ありますし、
それこそめっちゃ稼いでいるゲームのサーバサイドがRubyだったりも普通にありますΣ(゚Д゚)ガーン *11

Rubyはとにかく日本語に強く、文字コードの変換をこれだけ精密かつ簡単にできる言語って、
他にはあまりないと思います
その意味でも「日本国内のWebサービス」って文脈でRubyは強力な候補です

なにより、Rubyのコミュニティに(日本人の)有名人が多いってのも、
コミュニティでのつながりがほしい人には有利かと


いずれにせよ、こういったデータは「バイアスがどのようにかかっているか?」を検討する必要があり、
今回の場合であれば「GitHubを使っているプログラマ」が主体なので、
GitHubを使ってないプログラマのトレンド」とか、「求人側のトレンド」が考慮されてません

エンジニアの募集用件に「Go」とか入っていたとしても、
実際に入ったらメインのプロジェクトはPHPとかRubyで、
そちらのメンテに回される・・・なんてことはいくらでもありますからね(´-ω-)

【2018年最新版!】人気プログラミング言語を徹底比較! | TechAcademyマガジン
indeed.comの2016年の求人情報がベースであり、海外の傾向)

2017年5月29日 - 【調査レポート】Go言語、Pythonの案件・求人に増加の兆し。一方COBOLエンジニアのニーズは低落~レバテック2016年度エンジニア人材市場動向レポート~|レバレジーズ株式会社
(自社に登録された求人情報の分析なので、つきあっている会社に依存する)

プログラマー年収ランキング2017!言語別、第1位はScalaの626万円 | みんなのスタンバイ
(なぜか「CがあるからC++C#を除いた」となっており、C#の動向が不明)

2018年の人気プログラム言語10選を徹底比較!気になる年収や求人、学習難易度まで|トイロハ
(データ元が「エンジニアに特化した転職サービス」ではない)

どれが正しい・・・ということではなく、
バイアス(や書いた人の立ち位置)も考慮しながら検証していくのが大事かなと(´-ω-)

あとはまあ、本文でも書いたとおり、ここに挙げたどの言語に触っていたとしても、
それを「プロとして仕事ができる程度」まで習熟しているなら、
Goを書くのはそんなに難しくないですし、あせらなくても良いかと

*1: ここは批判の対象になっているようですが、後述するように、「本来のGoの適用領域」からするとむしろ、「一つのバイナリ単位で環境を分ける」くらいでもいいのでは・・・と思います なんなら、direnvを使ってプロジェクトディレクトリごとにGOPATHを切り替えれば解決するわけですし

*2: 強いていえば、「構造体」といわれてメモリ空間が意識できるなら、という前提はあるかもしれません まあ、どんな言語であれ、メモリ空間を意識できるかは重要です

*3: なぜ釣り合わないのかについて、一度は長々書いたのですが、どんどん本題からずれていってしまうので、ばっさり切りましたΣ(・ω・ノ)ノ

*4: 初期のGCEとかHadoopとか

*5: ErlangとかScalaのAkkaとか

*6: https://parrot.hatenadiary.jp/entry/2018/07/27/162939

*7: かつてもRubyで書いたシステムのバックエンドをScalaで置き換えるとかありましたよね? わりと有名な「Twitter」ってサービスですがΣ(・ω・ノ)ノ

*8: だからこそ、GooglePythonに対応しても、Rubyには対応しません(´-ω-)

*9: サーバサイドJS=Node.jsに関しては・・・私も仕事で触ったことがありますが、「API+フロント」の文脈でいえば、「WebAPIを作るにはちと辛い」印象です 「向いてない」というより、「他にもっと楽な実装をできる言語があるでしょう?」という意味で(´-ω-) 逆に、リアルタイム性を求められるコンテンツにおいては圧倒的な性能を誇るわけで、やはり「どこで何を使うのが適切か?」を考えないといけません

*10: 公開されている事例の一つ https://qiita.com/gomi_ningen/items/ce20176d86276fce71e3

*11: 私も実際、スマホゲーのサーバをRailsで書いていたわけで・・・