goa へのプルリクエストの送り方

goa へのプルリクエストの送り方について 3 回に分けて解説する連載記事です。これを見れば誰でもコントリビュートできるようになるはずです!

目次

  1. goa へのプルリクエストの送り方 (準備編)
  2. goa へのプルリクエストの送り方 (プルリクエスト編)
  3. goa へのプルリクエストの送り方 (バックポート編)

goa勉強会 in 六本木一丁目で発表してきた

発表してきました。

connpass.com

国内の goa の勉強会としては golang: goa勉強会に次いで 2 回目になるかと思います。当日カミングアウトしましたが私はまだ goa の本番運用をしたことがないので、実際にサービス運用している視点での話がたくさん聞けてよかったです。早く本番デビューしなければ…。

goa の改善と改良

The improvement and enhancement of goa

主催の @deadcheatgreat さん、そして会場提供して下さった istyle さんありがとうございました。参加した皆さまお疲れさまでした。

goa 公式サイトを日本語翻訳した & goa の開発メンバーになった

goa 公式サイトを日本語翻訳した

昨年始めた goa 公式サイトの日本語翻訳が終わりました。

goa.design

日本の開発者にあまり使われてないのは日本語のリソースが少ないからでは、ということで昨年末に ikawaha さんとプロジェクトを開始したのですが、結構分量があったので数ヶ月かかってしまいました。細かい修正は残っているものの、一旦は年度内に完了できてよかったです。 Go で Web API の開発を行う際には是非 goa を候補に加えてみて下さい。

goa の開発メンバーになった

2 月末に goa の開発メンバーになりました。

先日アナウンスされた v1.2.0 のポストでも大きく取り上げてもらいました。

goa.design

以下、引用です。

Taichi was one of the first contributors to goa, his contributions are always of the highest quality. Apart from fixing many bugs and contributing actively to goa v2, Taichi also helped translate the entire https://goa.design/ja website into Japanese.

日本語だと以下のような感じでしょうか。

Taichi は goa の最初のコントリビュータの一人で、彼のコントリビューションはいつも最高のクオリティです。 Taichi は多くのバグ修正や goa v2 にアクティブに貢献している他、 https://goa.design/ja の Web サイト全体を日本語に翻訳するのにも尽力しました。

惜しみない賞賛です。少し照れます😅

2016 年の春くらいから goa を使い始めて、次第にプルリクエストを送るようになりました。 GitHub や Slack でやり取りをするうちに誘われて v2 の開発にも参加するようになり、今回とうとう goa の開発メンバーに加わりました。一応 push 権限を与えられているのでコミッタと呼べそうな気もしますが、今まで通り一人のユーザ、そしてコントリビュータとして goa の開発に携わっていければと思います。

おまけ

翻訳プロジェクトの打ち上げ。最高の肉だった。

f:id:tchssk:20170418161333j:plain

なぜ goa の DSL はブランク識別子への代入が必要なのか

goa のトップレベDSL

goa の design は DSL をネストさせながら記述しますが、その一番上の階層に来るものをトップレベDSL と呼びます。標準で用意されている apidsl では以下の DSL がそれに当たります。

  • API()
  • Resource()
  • Type()
  • MediaType()

前提として、すべての DSL は Go の関数であり、それを用いて記述される design は Go のソースコードです。

トップレベDSL の記述

goa ではトップレベDSL を以下のように記述します。

var _ = API("cellar", func() {
    // Definitions.
})

なぜ以下のように書けないのでしょうか?

API("cellar", func() {
    // Definitions.
})

Go の言語仕様

まず Go の言語仕様を確認します。

Go の言語仕様ソースファイル構成 という仕様が明記されています。それによるとソースファイルは以下の 3 つのブロックから構成されます。

この「トップレベル宣言」に含まれるのは以下の宣言です。

  • 定数 const
  • type
  • 変数 var
  • 関数・メソッド func

Go のコードとして見た API() DSL

翻って API() DSL を Go のコードとして見てみましょう。

var _ = API("cellar", func() {
    // Definitions.
})

上記の DSL は大きく以下の 3 つに分割することができます。

  1. API() という関数の呼び出し (Calls)
  2. var による変数宣言 (Variable declarations)
  3. = による代入 (Assignments)

総合するとこのコードは「代入を伴った変数宣言」であり、前述した Go のトップレベル宣言として有効です。

小ネタ

本来 var による変数宣言では型の指定が必要ですが、ここでは代入を伴っているため型推論が働いています。もちろん以下のように明示的に型の指定を行うこともできます。

var _ *design.APIDefinition = API("cellar", func() {
    // Definitions.
})

ブランク識別子への代入がないとどうなるか

もう以下の書き方がなぜ駄目なのかわかりますね。

API("cellar", func() {
    // Definitions.
})

API() は関数呼び出しであり Go のトップレベル宣言として記述することはできないのです。

結論

Go の言語仕様的にトップレベルに書けるのは以下のいずれかの宣言であるため、代入を伴った変数宣言とする必要があるから。

  • 定数 const
  • type
  • 変数 var
  • 関数・メソッド func

2016 年振り返り

勉強会

勉強会で発表しました。

tchssk.hatenablog.com

これは本当にいい経験でした。発表を通じて人と知り合えたのも良かったですね。

OSS

半年で 21 件、通年だと 34 件プルリクエストを出しました。

Search · author:tchssk created:2016-07-01..2016-12-31 · GitHub

8 割くらいは goa に対するものでした。やろうと思っていた goa のドキュメント翻訳にも着手したので、なるべく早く終わらせたいですね。モタモタしていると v2 が出てしまいそうだし。

それから自分自信のプロジェクトもいくつか始めました。これも goa 関連 (goa 好きすぎかw) 。

tchssk.hatenablog.com tchssk.hatenablog.com

ISUCON

そういえば予選に参加したのに惨敗だったこともあって記憶がおぼろげです。忘れたいのかもしれない ... 。

総括

goa に始まり goa に終わる 1 年でした。

ソフトウェアエンジニアとして数多くの OSS を使わせて頂いていている中で、いつかそれらに恩返ししていきたい、という想いがずっとありました。今年はほんの少しだけそれを遂げられたかな、と思います。

Swagger 定義から goa の design を生成する ago という CLI を作りはじめた

これは Go (その2) Advent Calendar 2016 の 17 日目の記事です。

ここ半年ほど goa というフレームワークを気に入って使っているのですが、思うところがあって goa に関連する ago という CLI を作りはじめました。この記事では、簡単な goa の説明から、今回の開発に至った経緯と、このツールで行えることについて記述します。

goa とは

Go でマイクロサービスな Web API を作るためのフレームワークです。

github.com

goa の DSL で design と呼ばれる定義を書いたら、 goagen というジェネレータを使ってサーバやクライアントなど各種のコードを生成することができます。毎度リンクを貼らせて頂いているのですが @ikawaha さんによる連載記事が本当にオススメです。

ikawaha.hateblo.jp

goa 流行らない問題

そうなんです。私も良さを広めたいユーザの一人なんですがなんか流行らないんです。参考までに他の Web フレームワークGitHub のスター数を比較してみました。 (2016/12/17 時点)

Repository Since Stars
https://github.com/gin-gonic/gin 2014/06/15 8294
https://github.com/labstack/echo 2015/03/01 6034
https://github.com/goadesign/goa 2015/10/18 1613

そして Google Trends の人気度推移。

開発が開始された時期の違いはあるにしてもあまりにも大きな差ですね。

ではなぜ流行らないのか。この理由を定量的に説明するのは難しいですが、おそらく goa のユニークな開発アプローチがその参入障壁を高くしてしまっているのだと思います。

  • 専用の DSL で design と呼ばれる設計書を書く
  • design を元にアプリケーションコードの大部分を自動生成する

goa での開発においてこれらのステップは必須です。避けて通ることはできません。 Go の Web フレームワークを net/http, gin, echo, ..., goa と横に並べて比較したとき、 goa の毛色が他と大きく異なることは明らかです。 Go を長く使っているユーザほど、それが「シンプルで、信頼でき、効率的なソフトウェアを構築しやすくする」という Go の思想に反していると感じてしまうかもしれません。

しかし一度 DSL を覚えてしまえばアプリケーションのインタフェース (リクエストとレスポンス) はすべて design に記述されているという見通しの良さが手に入りますし、大規模にコード生成を活用している点なども含めて実際は実に Go らしいフレームワークだと思います。

既存の Swagger プロジェクトの goa への移行問題

少し話は変わって Open API Initiative への採用も記憶に新しい Swagger です。実際に Swagger を使っているプロジェクトも増えているような気がするのですが、既存の Swagger プロジェクトを goa に移行したいというニーズがあるようです。

goa は標準で Swagger をサポートしており、 Swager の公式ページにも記載されています。しかし、そのサポートの意味は「 Swagger 定義の出力」であり「 Swagger 定義からのコード生成」ではありません。 goa は Swagger とよく似たワークフローを採用していますが、その中心にあるものが違います。 Swagger を用いた開発の中心にあるのは「 Swagger 定義」であり、そこからアプリケーションコードを生成しますが、 goa を用いた開発の中心にあるのは「 goa の design 」であり「 Swagger 定義」はアプリケーションコードと同じ生成物のひとつに過ぎないのです。

goa を用いる以上 design を中心に据えた開発を行う必要がある、しかし Swagger ユーザに goa への移行パスは用意したい、それを可能にするにはどうすればいいか。 Swagger 定義から goa の design を生成するコマンドがあれば Swagger ユーザはスムーズに goa を使い始められるのではないでしょうか。

ago

ようやく本題です。 ago というコマンドを作り (はじめ) ました。

github.com

使い方は簡単です。

$ ago swagger swagger.json > design.go

このように swagger.json を引数として渡すと標準出力に goa の design が出力されます。本当はきちんと完成させたかったのですが間に合わなかったため完全な design は出力されません orz しかし design を構成する DSL の 1/3 程度は既にサポートしているので既存の Swagger 定義がある場合は goa 導入の助けになると思います。鋭意開発中なので近日中にすべての DSL がサポートされる予定です。

あとがき

実際このツールのニーズはかなり局所的な気もしているのですが、既に Swagger を使っている方は試してみていただけたら嬉しいです。また何より、 goa に少しでも興味を持った方はこのフレームワークに触れてみて、その素晴らしさを体感してみて欲しいと思います。

Riot.js を使ってみた

少し前ですが、ちょっとウェブアプリケーションを作る機会があったので使ってみました。

Riot.js とは

http://riotjs.com/ja/riotjs.com

A React-like user interface micro-library の謳い文句通り React ライクなライブラリです。つい最近 v3 がリリースされたみたいです。私が使ったバージョンは v2.5.0 でした。公式のガイドで大枠を掴んだら examples で具体例を見ることができます。

Riot.js でウェブアプリケーションを作る

Riot は MVC でいう View のためのライブラリでありフレームワークではありません。アプリケーションを作る際には自分で枠組みを考える必要があります。

tag の分類

React (Redux) ではコンポーネントを Presentational components と Container components に分類する考え方があるようなのでこれを取り入れてみました。前者は表示のみを行うステートレスな (= 状態を持たない) コンポーネントで、後者はそれらに具体的なデータを与えるステートフルな (= 状態を持つ) コンポーネントです。

qiita.com

今回は各画面のルートコンポーネントのみを Container Components とし、残りはすべて再利用可能な Presentational Components として実装しました。

ディレクトリ構成

以下の構成としました。

    .
    ├── config
    ├── public
    │   ├── assets
    │   │   └── images
    │   │   └── js
    │   │       └── bundle.js
    │   └── index.html
    └── src
         ├── stores
         └── tags
             ├── components
             ├── containers
             └── mixins
  • src/

    Riot の tag は tags/ に配置しています。汎用的な機能はミックスインにしておいて各々の tag から利用しています。 stores/ にはバックエンドの API と通信を行う処理全般を配置しています。

  • public/

    画像などの静的ファイルを配置しています。 assets/js/bundle.jssrc/ 配下のファイルをコンパイルしたものです。

  • config/

    config のための JSON を配置しています。

ビルド

ES5 で書いているのでトランスパイラ (Babel) は使っていません。タスクランナー には gulp.js を使用しました。

  1. configconfig/ から設定を取得して src/stores/ 内の API の URL を置換
  2. riotsrc/ 配下のファイルを public/assets/js/bundle.jsコンパイル
  3. superstatic でサーバを立てて public/ のファイルを配信
  4. run-sequence で 1 から 3 を 順番に実行

上記のような task を作って gulp run で実行できるようにしています。また、開発中は都度コンパイルするのが面倒なので gulp.watch()src/ を監視して変更があったらリコンパイルするようにしていました。

感想

View のためのライブラリとして見たとき Riot は学習コストも少なく扱いやすい印象でした。 tag は見慣れた HTML / CSS / JavaScript が集合しただけのものなので、初見でも心理的抵抗が少ないように思います。共同で作業したデザイナ (非エンジニア) も 10 分ほどの説明ですぐに理解してくれました。ただウェブアプリケーションを作ろうと思ったとき参考になる情報が少なくて苦労する場面も多かったです。同じ View のためのライブラリである React には FLUX というアーキテクチャがあり、そのポピュラーな実装として Redux があります。 Riot でもそのあたりの話が多くなるとよりユーザが採用しやすくなるのではないかと思いました。