日記マン

動画広告プロダクトしてます。Go, Kubernetesが好きです。

HTTPリクエスト・レスポンスレベルのテストユーティリティ

JSON/XML 構造データのアサーション

HTTPのAPIは多くの場合、JSONXMLのフォーマットでレスポンスする。
実際にHTTPリクエストを投げて、期待するレスポンスを検証する際に、
ツリー構造であるJSONXMLに対し特定のフィールドのみ一致するかを検証したい場合が多い。
そんな時は、JSONならば mattn/go-scanXMLならば gopkg.in/xmlpath のパッケージが便利。

続きを読む

Apache Beam Streaming をGCPサービスに書き込む備忘録

Apache Beam のストリーミングモードによる実装 (Cloud Pub/Subからプルしてくるとか) で、

ファイルストレージサービスである Google Cloud Storage ,
NoSQLの Cloud Datastore ,
そして Cloud Firestore ,

へ書き込む方法を個人的備忘録メモ。
公式のexamplesにはなく、それでもわりと実装する機会があるので。

続きを読む

GoのコードからPlantUMLコードを生成する静的解析ツールを作っている

tl;dr

gouml の紹介

Goのコードを静的解析し、PlantUMLのコードを吐くパーサを開発している。

github.com

続きを読む

Go言語による「ネット広告」ビジネスに対するドメイン駆動設計の具体例

ネットに転がっているドメインモデリングの実例は少ない。
というのも、その性質上、扱うドメインに対し答えがバラバラで一般化できるものではないから。
というかそもそも外部公開できないような、競合と差別化要因となるロジックだったりするから。
だからこそ、DDDの解説は概念の域にとどまるものが多く、実践的なイメージは習得しづらい。

前回のエントリで、ドメイン駆動設計とはドメインに特化した型の設計と書いた。

i101330.hatenablog.com

次は、その具体例を、
「ネット広告」をドメインに、
Go言語による型の実装とともに考察してみる。

続きを読む

ドメイン駆動設計のドメイン駆動とはなにか

ここ最近の仕事は、かなり硬直化した自社サービスをリファクタリングしている。
そのなかでアプローチのひとつとして、ドメイン駆動設計を勉強して、取り組んでいる。
エバンスDDD本を手に取り、ネットで様々な知見を調べながらも、理解が定着してきている。
ここらでいちど、ドメイン駆動設計について、理解をアウトプットしておく。

続きを読む

Goにおけるドメインオブジェクト設計の考察

仕事で、PHPで書かれた硬直したWebサーバシステムを、Go言語でリプレイスしています。
Go言語本来のらしさを壊さず、ドメイン駆動のオブジェクトパラダイムを導入する際の、
自分なりの設計方針を公開して、オープンに意見交換などができればと思いブログにしました。

tl;dr

Goでどのようにデータにロジックを寄せたリッチなドメインオブジェクトを設計するか、
また、例として動画配信サービスを開発するというシナリオでモデルを洞察していき、解説を試みます。
最後に、値オブジェクトの設計方針について簡単に言及しました。

続きを読む

Go言語の例外を必ず扱うような言語機能のありがたさ

僕はGo言語が好きだ。そのGoがもたらす恩恵のひとつとして、例外周りのセマンティクスがある。
Goでは例外はerrorという型の値に抽象化され関数の返り値として記述することが多いというのはご存知だと思う。

func GetUser(id int) (*User, error) {
    // do some thing ...
    if err != nil {
        return nil, err
    }

    return user, nil
}

上記の例のように、複数の返り値を設定できる言語機能を利用して、
第一にその関数に期待する主要な出力のデータ、第二に関数内で発生した例外(error型の値)を伝播させるのが一般的な記述だ。

この if err != nil {return err} を毎回書くのが(たとえコピペでも)
「めんどくさい」、「冗長だ」という意見を持つプログラマもスクなくはない。
個人的には気持ちはわからなくもないが後述する理由と別にそこまで苦に思うような記述量じゃないと思っているが
TwitterのTLでも何度かこの批判的な声はよく界隈を賑わしている。

僕は、むしろ、このセマンティクスには肯定で、どちらかというとありがたい恩恵をもたらしていると思っている。
その恩恵というのは、感知すべきバグを埋もれさせてしまうことを防ぐ一助になっているからだ。
実際に僕はGoでアドサーバAPIを書き、運用を初めてから潜在したバグもなく稼働し続けることに成功している。

早期returnの記述が多くなりやすい

まず第一にGo言語は手続き的な記述に優れたシンタックス・セマンティクスを提供している。
それゆえ、手続きは上から下に流れていく。その上から流れる手続きのなかで、
外部関数を呼び出した際のerror検知は、基本的に早期returnの記述が多くなる。
上記の例でもあったように、

   if id < 0 {
        return nil, fmt.Errorf("invalid user id")
    }
    // ここから先はidが不正な値であるケースを
    // 考慮しなくてよくなる
    user := &User{ID: id}
    if err := db.Get(user); err := nil {
        return nil, err
    }
    // ここから先は外部呼び出しの例外(DBからGetできなかった)のケースを
    // 考慮しなくてよくなる
    // do something ...

上から下へと理路整然と記述される手続きにおいて、
if err != nil {return err} は例外のケースを取り除いていき、
手続きの内容がシンプルに洗練されていく。
これによりコーディングもコードリーディングも、考えうるケースというのを不必要に増大させない効果をもたらしている。
その習慣的なフレームワークにより、バグを生みにくいプログラムコードを書くことができると思う。

めんどくさいけどやらなきゃいけないことにシンプルなインターフェイスを提供している

ここからは個人的に他の言語にある try-catch による例外機構と比較していく。
意見のわかれるところであり、論争に発展しそうな話題である。

まず。例外処理はやらなきゃいけない。
でも僕個人はめんどくさがりで、 うまくいくことを記述することがなによりも楽しい。
そうしたときに、try-catchをサボりたくなる。
一度うまくいった場合しか想定しないコードを書いた後で、try-catchを書くのは結構めんどくさいと思ってしまう。
ネストしないといけないし、スコープのこととか、どの粒度が適切か、今一度リファクタリングの必要を与える。

そんなめんどくさい例外処理というのを、Go言語は、
if err != nil { return err } という極限までシンプルなインターフェイスによって
必ずしないといけない制約を設けている。
これは、もたらしてくれる恩恵にくらべれば、メンドくさがりやの僕でも、このルールくらい全然守れる。