読者です 読者をやめる 読者になる 読者になる

Model View Whatever + Rx のアンチパターン

GUIアーキテクチャパターンとしてModel View Whateverを採用した際に、Rxのストリームをプレゼンテーション層からモデル層まで一気通貫でつなげてしまうのはアンチパターンである、という話をします。

前提

GUIアーキテクチャパターンにおける Model View Whatever パターン、とくにMVVMに近いパターンを前提とします。いわゆるサーバサイドの「web系MVC」は前提としません。

Model View WhateverパターンとPDS

そもそもGUIアプリケーションでModel View Whateverというアーキテクチャパターンを採用する理由として、PDSの実現があります。このあたりの話は詳しくは実況中継シリーズ Vue.jsで実現するMVVMパターン Fluxアーキテクチャとの距離 - Re.Ra.Ku アドベントカレンダー day 13 - Re.Ra.Ku tech blogを参照してください。

そして、リッチクライアントにおいてモデルはステートフルです。状態管理というのは非常に複雑なものです。この複雑なものを、GUIプラットフォームの都合に振り回されるプレゼンテーション層からひっぺがして、モデル層で独立に設計、管理できると、コードの見通しもよくなるしテストもしやすくて嬉しいね、というのが、リッチクライアントにおいてM V Whateverアーキテクチャパターンを採用する動機のひとつです。

これを徹底すると、モデル層とプレゼンテーション層のコミュニケーションは、以下のようになっているべきです。(参考:MVVMのModelにまつわる誤解

  • プレゼンテーション層 -> モデル層のコミュニケーションは、voidなメソッドの呼び出しと、属性の取得のみ行われる
  • モデル層 -> プレゼンテーション層のコミュニケーションはイベントの発行のみ行われる(MVPの場合Presenterで定義されるインターフェイスの呼び出しのみ行われる)

モデル層とプレゼンテーション層のコミュニケーションを上記のように整理、制限を持たせることによって、モデル層はプレゼンテーション層に依存しないで済むようになる、というのがそもそもMVWのアイデアです。

具体的な例

たとえば、API通信を伴う操作を例に取りましょう。ある画面で、ボタンをタップするとAPIから情報を取ってきて、それを画面に表示するとしましょう。

この場合、例えば一気通貫に

rx.tap
 .flatMap { // API通信を伴う操作。失敗時にはonErrorが呼ばれる  }
 .subscribe {
   onNext: { // APIの結果から表示を操作 }
   onError: { // エラーの型を見て分岐 }
 }

という感じで書くのではなく、

////////////////
// in presentation
////////////////

rx.tap
 .subscribe {
   onNext: { service.invokeNyan(param) }
 }

someModel.xxEvent.subscribe {
   onNext: { //someModelの状態に応じてViewを描画 }
}

errorModel.nyanErrrorOccured.subscribe{
   onNext: { //nyanErrorに応じたViewの描画 }
}

errorModel.wanErrrorOccured.subscribe{
   onNext: { //wanErrorに応じたViewの描画 }
}

///////////////////////
// in model
///////////////////////

// service
func invokeNyan(param) {
    validate(param).flatMap {validatedParam =>
      return api.dispatch(validatedParam)
    }.subscribe {
      onNext: {
          // データ・モデルやドメイン・モデルを操作。
          // MVVMなら、モデルの状態変化の結果として、イベントがdispatchされる
          // MVPならPresenterのインターフェイスを叩く
      }
      onError: {
          // エラー種別に応じてエラーモデルやデータ・モデルを操作
          // MVVMなら、モデルの状態変化の結果として、イベントがdispatchされる
          // MVPならPresenterのインターフェイスを叩く
      }
    }
  }
}

こういうふうに書いたほうが良い、ということです(擬似言語によるコードです)。

まず、前者の場合(そもそもtapがonErrorに入らないとかそういう問題もあるんだけど話がそれるので置いておきます)、まず「エラーの型を見て分岐」というロジックがプレゼンテーション層に漏れ出していますが、後者の場合、「このユースケースではAPIからnot foundエラーが返ってきてもエラーとせず単に空白表示にするが、あのユースケースの場合APIからnot foundエラーが返ってきた場合はエラーとして扱う」みたいな「ユースケースに応じたロジック」をモデル層に隠蔽することができます。(ユースケース依存のロジックなので、この分岐ロジックはアプリケーションサービス的な層に書かれることになるでしょう)

また、前者の場合、「このAPIを叩いた結果によってあのデータ・モデルの状態がこのように変化する」というようなロジックがこれまたプレゼンテーション層に漏れ出してしまう一方、後者の場合「このAPIを叩いて、成功すればこのデータ・モデルがこう変化し、not foundの場合はあのデータ・モデルがこう変化し、想定していないエラーが怒ったらエラー・モデルが変化し」という「アプリケーションの論理的な共同」をモデル層に閉じ込めることができています。

これは、ストリームの発生元がtapイベントであろうとAPI呼び出しであろうと同じことです。モデル層の奥深くや、プレゼンテーション層で発生したイベントを、PDSの境目を超えて一気通貫で扱おうとすると、PDSを成り立たせている「プレゼンテーション層とモデル層のコミュニケーションのルール」から外れてしまい、PDSが崩壊します。

別の例として、UIのイベントとはストリームを繋がなかったけど、非同期でAPIを叩いた結果をObservableで返したものを、そのまま返り値としてプレゼンテーション層まで返して、プレゼンテーション層でsubscribeしてしまう、というのもまた、アンチパターンであると言えるでしょう。あくまで、プレゼンテーション層からはvoidなメソッドを叩いて、APIから返ってきた非同期な値はモデル層内でsubscribeしてハンドルし、データ・モデルやドメイン・モデルに変化を起こす(その変化をプレゼンテーション層で知るためにはモデル層がイベントを発行する)、という形にするべきでしょう。

まとめ

まとめもなにも、「GUIアーキテクチャパターンとしてModel View Whateverを採用した際に、Rxのストリームをプレゼンテーション層からモデル層まで一気通貫でつなげてしまうのはアンチパターンである」が結論なのですが、もっと具体的なところまで話をしてしまうと、Model View WhateverパターンにおいてRxのストリームは以下のように使うのがよいお作法なのではないでしょうか。

  • プレゼンテーション層においては、UIイベントのストリームを論理的な意味のあるイベントのストリームへと変換する(たとえばrx.tapイベントのストリームをまとめて「ダブルタップされた」というイベントのストリームに変換するなど)のみに留める
  • モデル層においては、Rxが「アプリケーションの論理的な挙動」をうまくモデリングできる部分に自由に使う
  • モデル層からプレゼンテーション層へのイベント通知のためにモデルにPublishSubjectやBehaviorSubjectな属性を持たせるのはアリでしょう

Re.Ra.Ku アドベントカレンダー 2016 まとめ

今年もアドベントカレンダーの季節が終わりました。

今年は弊社もアドベントカレンダーに参加しよう、と決めてから、少ないメンバーで担当を回しながら書いてきましたので、せっかくなのでリンクをまとめておきたいと思います。興味のあるタイトルがあれば、ぜひ読んで下さい。

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

techblog.reraku.co.jp

来年はもっとたくさんのメンバーでアドベントカレンダーが実施できるよう、会社もプロダクトも成長させていきたいと思っております。

どうぞよろしく!

労働の理由と労働の環境について - Re.Ra.Ku アドベントカレンダー day 25

リラクアドベントカレンダーの最終日です。丸山です。せっかくなんで、最後はポエムで締めましょう!

わたしは現在リラクでマネージメント職として働いています。自分でもコードを書いているので、かっこよく言えば一応「プレイングマネージャ」という感じでしょうか。ただ、弊社は優秀なプログラマが集まっており、なおかつ今は人数も多くないため、彼らをマネージメントするにあたって困ることはほとんどありません。どちらかというとプロダクトに関わるステークスホルダー間の調整のほうが消耗することが多い、という感じの日々で、人的な部分で悩むことが少なく、本当にメンバーには感謝しています。

さて、「プロダクトに関わるステークホルダー間の調整に消耗する」と書いていますが、これはどちらかと言うと自分の問題で、単にわたしに調整力のようなものが欠けている、というのが問題だと感じています。苦手なことをするのは本当に大変です。今回は、「そんな苦手なことをやってまでなぜこの会社で働くのか」ということについて書いてみたいと思います。

夢のないことを言うようですが、わたしが働く第一の理由は、金です。家族が楽しく生きていくのには金がかかるし、息子の教育にだってお金がかかります。そのためにわたしは労働し、お金を稼いでいます。

でも、それだけでは心のどこかがどんどんすり減っていきます。わたしはわがままで強欲なので、せっかく働くならば以下の楽しみも同時に摂取したいと思ってしまいます。

  • 自分の能力が誰かを幸福にしていると信じられる
  • 技術的にチャレンジングな環境で働ける

以前自分のブログでも書いたことがありますが、労働というのは基本的に世界への働きかけです。例えば農業は自然を人間にとって都合の良いように改変することにほかなりません。そのように、どんな労働だって多かれ少なかれ「世界を変えている」と思います。そして、どんな労働も、少しは世界を変えている以上、「無垢」ではあり得ないと思っています。世界を変化させることは、だれかを傷つけることとコインの両面のようなものであると思います。だから、だれかの特定の仕事を「あれは不幸を生み出す仕事だ」と断罪することはとてもむずかしいことだとわたしは思います。だれにとって何が不幸であるのか、というのは一面から判断できることではないでしょう。

でも、自分の仕事については、自分で選択することができます。

「仕事だからしょうがないんだよ」と思い、「自分の技術で不幸な人間をたくさん生み出すのはしょうがない」と思いながら仕事をするのか、「自分の技術でこのサービスを作ることで、総量としては幸せが増えるはずだ」と信じながら仕事をするのか、そこには大きな違いがわたしにとってはあります(そこに大きな違いがないひともいると思うし、それはそれでいいと思ってます。あくまで自分の話をしています)。

消耗する仕事も日々のなかにはあるけれど、それでも自分の労働によって生み出すものは世界の幸福の総量を増やせるものであろうと信じて日々労働をすることができることは、わたしにとっては幸福なことです。こう思えるのは、会社が目指す方向と自分の目指す方向が大体一致している、というのが大きな理由ですね。

技術的にも同じような話で、いくら自分の目指す方向と会社の目指す方向が一緒でも、プログラマとしてつまらない仕事しかないならばわたしはそこで働きたくありません。幸い、弊社のプログラマメンバーはみんな私よりもずっと優秀な技術者で、彼らと働くことはわたしにとってかなり大きな刺激になっています。

わたしは、自分の働く理由が「正解」だとは思っていません。というか、働く理由に正しさなんてないと思っています。どんな理由でもいい。第一、わたしの働く理由の第一は「金」ですし。ただ、自分の働く理由と向き合ったときに、その理由にふさわしい場所でふさわしい労働をできているならば、それは幸福のひとつの形であろう、と思っています。

めちゃめちゃスピリチュアルで薄っぺらいような話をしてしまいましたが、せっかくの年末年始、自分が働く理由と向き合って見ました。

みなさんが働く理由はなんですか? 正解なんてないと思いますが、みなさんの働く理由と働く環境がマッチした、幸福な来年になりますように! たとえばとにかく楽に働きたいというひとはとにかく楽な労働ができますように! 労働を一切したくないひとは労働しなくてもよくなれますように(めっちゃ努力が必要そう……)! 良いお年を!!!!

型安全なサンタクロース クリスマス前にコンパイルエラー - Re.Ra.Ku アドベントカレンダー day 24

アドベントカレンダー24日め。本日はクリスマス・イブです! サンタクロースのみなさんは無事にプレゼントを用意できましたでしょうか?

ところで、クリスマスといえば、となりのヤングジャンプなどで連載されている「ブラックナイトパレード」、面白いですね。この作品で初めて知ったのですが、クリスマスは良い子には赤いサンタがやってきてプレゼントをくれる一方、悪い子のところには黒いサンタがやってきて石炭をくれるという文化があるそうですね(なぜ石炭なんだ……)。

今日はせっかくのクリスマス・イブなので、これをソフトウェアとしてScalaでモデリングしてみましょう!

まずは型を定義しよう

さて、まずはサンタクロース、プレゼント、子供の型をそれぞれ定義します。

trait SantaClaus

trait Child

trait Gift

サンタクロースには赤いサンタと黒いサンタがおり、子供には良い子と悪い子がいます。また、プレゼントにはおもちゃと石炭を用意しておきましょう。

trait SantaClaus
class RedSantaClaus extends SantaClaus {
  override def toString: String = "赤いサンタクロース"
}
class BlackSantaClaus extends SantaClaus {
  override def toString: String = "黒いサンタクロース"
}

trait Gift
class Toy extends Gift {
  override def toString: String = "おもちゃ"
}
class Coal extends Gift {
  override def toString: String = "石炭"
}

trait Child
class GoodChild extends Child {
  override def toString: String = "良い子"
}
class BadChild extends Child {
  override def toString: String = "悪い子"
}

それぞれがモデリングできました。今回はアプリケーションのエントリポイントに、giveGiftというメソッドを生やして、サンタが子供にプレゼントを上げるという行為をモデリングしてみましょう。

object Xmas {
  def main(args: Array[String]):Unit = println(giveGift(new RedSantaClaus, new GoodChild, new Toy))

  def giveGift(s: SantaClaus, c: Child, g: Gift) = {
    s"${s}が${c}に${g}をあげたよ!"
  }
}

このプログラムを走らせると、「赤いサンタクロースが良い子におもちゃをあげたよ!」が出力されますね。よかった、たかしくんもにっこりです。

しかし、よく考えてみましょう。このプログラムは本当にクリスマスをきちんとモデリングできているでしょうか。もしもmainメソッドを以下のように書き換えたら?

object Xmas {
  def main(args: Array[String]):Unit = println(giveGift(new RedSantaClaus, new GoodChild, new Coal)) // !!!!

  def giveGift(s: SantaClaus, c: Child, g: Gift) = {
    s"${s}が${c}に${g}をあげたよ!"
  }
}

「赤いサンタクロースが良い子に石炭をあげたよ!」と出力されました。これではせっかく良い子に過ごしていたたかしくんが可愛そうです。このような事故をなんとかして防ぐことはできないでしょうか……。

このような悲しい事故を防ぐためには、giveGiftの引数の型の組み合わせを制限してあげればよさそうです。Scalaではそのようなときに型クラスを利用することで型に制限をつけることができます。

scalaでの型クラスについては手前味噌ですがScala の implicit parameter は型クラスの一種とはどういうことなのかを参照してください。

まずは制約のためにTypeClassedXmasという型クラスを定義し、「赤いサンタと良い子とおもちゃ」の組み合わせ、「黒いサンタと悪い子と石炭」の組み合わせをそれぞれ型インスタンスにしましょう。

object Xmas {
  trait TypeClassedXmas[S <: SantaClaus, C <: Child , G <: Gift]
  implicit object GoodChildXmas extends TypeClassedXmas[RedSantaClaus, GoodChild, Toy]
  implicit object BadChildXmas extends TypeClassedXmas[BlackSantaClaus, BadChild, Coal]

  ...
}

そして、giveGiftメソッドは型パラメータを取りimplicit parameterでこの型クラスを受け取るようにします。

  def giveGift[S <: SantaClaus, C <: Child, G <: Gift](s: S, c: C, g: G)(implicit ev: TypeClassedXmas[S, C, G]): String = {
    s"${s}が${c}に${g}をあげたよ!"
  }

さて、これでgiveGiftの引数は「赤いサンタと良い子とおもちゃ」の組み合わせか「黒いサンタと悪い子と石炭」の組み合わせ以外を受け取ったときにコンパイルエラーとなるようになりました!

object Xmas {
  trait TypeClassedXmas[S <: SantaClaus, C <: Child , G <: Gift]
  implicit object GoodChildXmas extends TypeClassedXmas[RedSantaClaus, GoodChild, Toy]
  implicit object BadChildXmas extends TypeClassedXmas[BlackSantaClaus, BadChild, Coal]

  def main(args: Array[String]):Unit = {
    println(giveGift(new RedSantaClaus, new GoodChild, new Toy))
    println(giveGift(new BlackSantaClaus, new BadChild, new Coal))
    // println(giveGift(new BlackSantaClaus, new GoodChild, new Coal)) -> コンパイルエラー!!!
  }

  def giveGift[S <: SantaClaus, C <: Child, G <: Gift](s: S, c: C, g: G)(implicit ev: TypeClassedXmas[S, C, G]): String = {
    s"${s}が${c}に${p}をあげたよ!"
  }
}

これであわてんぼうの黒いサンタも赤いサンタも、間違えたプレゼントを間違えた子供にプレゼントしようと思ったら、クリスマス実行前にコンパイルエラーになるようになりましたね!

今年もすべての子どもたちが幸せになれるクリスマスだと良いですね。それでは、We wish you a merry Xmas and a happy New Year!

gitをインストールしたらまずやっておきたい2つのこと - Re.Ra.Ku アドベントカレンダー day 23

こんにちは、神場です。

今回はgitに関する記事です。さっそくですが、タイトルにあります2つのこととは

  • エイリアス
  • グローバルなgitignore

です。

何番煎じなんだろうという感じもありますが、本当に便利な機能なので、あらためて記事にまとめるのも意味があるのかなと思いたいですます。

なお自分の環境がMacなので、以下はMacの設定になります。(Windowsユーザーの方ごめんなさい。

エイリアス

よく使うgit statusのようなコマンドは毎回打つと疲れてしまうので、git stのようにエイリアスを設定して短くすると楽になります。

設定方法(ユーザーごとに設定する方法)

一つずつ設定する場合は、上記の例だとgit configを使って

git config --global alias.st status

のようにします。

まとめて設定する場合は~/.gitconfig

[alias]
    st = status
    b = branch

のように書きます。

エイリアスの例

以下は自分の場合の例ですが、

~/.gitconfigの例

[alias]
    st = status
    b = branch
    co = checkout
    pu = push -u
    sh = show
    a = add
    aa = add .
    p = pull
    c = commit
    l = log
    d = diff
    cleanup = "!git branch | grep -v master | grep -v develop | xargs git branch -D"

このぐらい書いておくとかなりタイピングする数が少なくなります。 また、エイリアスで外部コマンドを呼び出すことも出来るので、上記のcleanupのように、より複雑な動作も書くことが出来ます。

その他のもっと便利な例としては以下の記事が参考になります。

グローバルなgitignore

プロジェクト単位ではなく、開発者の環境ごとに固有なディレクトリ・ファイルはグローバルなgitignoreを設定すると便利です。

gitignoreすべきディレクトリ・ファイルの具体例

具体的なものとしては

OS固有のもの

Macなら.DS_Store、WindowsならThumbs.dbなど。

IDE固有のもの

IntelliJの.idea/ディレクトリ、Xcodeのbuild/ディレクトリなど。

辺りでしょうか。

設定方法(ユーザーごとに設定する方法)

いくつかありますが、以下の方法がシンプルで良いかなと思います。

1. ~/.gitconfigexcludesfileを追加する

~/.gitconfigの例

[core]
    excludesfile = /Users/me/.gitignore_global
2. excludesfileで指定した場所に.gitignore_globalを置く

/Users/me/.gitignore_globalの例

.DS_Store

gitignoreの雛形

ここで指定する.gitignore_globalの雛形は gitignore.ioでWeb上で生成するか、giboというライブラリを使うのがおすすめです。

gRPCでサーバーとAndroid/iOSを通信する - Re.Ra.Ku アドベントカレンダー day 22

Re.Ra.Ku アドベントカレンダー 22日目です。

こんにちは。安部です。

ずっと気になっていたgRPCをせっかくの機会なので試してみました。

基本はgRPCの公式のサンプルとほぼ変わっていませんが、サーバー側とAndroid/iOSを連携するために必要なものをまとめてみました。

gRPCとは

grpc / grpc.io

A high performance, open-source universal RPC framework

Googleが作ったRPCフレームワークです。

gRPCでは様々な言語をサポートしていて、Protocol Buffersを使ってます。

Protocol Buffersのインターフェース定義からgRPCのコード生成できるようになっています。

gRPCインストール

Protocol Buffersの.protoファイルからコードを生成するためのビルドツールをインストールします。

Macを使っているので、今回はHomebrewを使ってインストールします。

$ brew tap grpc/grpc
$ brew install --with-plugins grpc

grpc/homebrew-grpc: gRPC formulae repo for Homebrew

protoファイル

Protocol Buffersのインターフェースの定義ファイルになります。インタフェース定義言語(IDL)を使って記述していきます。これを元にソースコードを生成します。

サーバーとクライアントの両方で同じファイルを使用するのでjavaやobjcの設定もあります。

詳しい仕様はProtocol Buffersのドキュメントを見てください。

メッセージとしてHelloRequestHelloReplyを定義して、GreeterというサービスでRPCのSayHelloメソッドを定義している感じです。

helloworld.protoで保存します。

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.star_zero.example.grpcandroid.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

サーバー側設定

今回はRubyでやります。ちょっと調べた感じGoで書いてるのが多い気がしましたが、私はGoがまだ分からないので…

セットアップ

$ bundle init

Gemfileを次のようにします。

source "https://rubygems.org"

gem "grpc"

bundle install

$ bundle install --path vendor/bundle

protoファイルからソースコード生成

protocというコマンドを使ってソースコードを生成します。

libディレクトリに出力するので事前にディレクトリを作成しています。helloworld.protoは一つ上の階層のprotosディレクトリに配置しています。パスは適宜変更指定ください。

$ mkdir lib
$ protoc -I ../protos --ruby_out=lib --grpc_out=lib --plugin=protoc-gen-grpc=`which grpc_ruby_plugin` ../protos/helloworld.proto

これを実行するとソースコードが2つ生成されていると思います。

  • lib/helloworld_pb.rb
  • lib/helloworld_services_pb.rb

サーバー側コード

かなり分かってないこと多いですが、先程のprotoファイルから生成されたコードを使ってRPCサーバーを起動しています。

この例ではもらったリクエストパラメータにHelloという文字列をつけて返却しています。

root = File.dirname(__FILE__)
$LOAD_PATH.unshift File.join(root, 'lib')

require 'rubygems'
require 'bundler/setup'
require 'grpc'
require 'helloworld_services_pb'

class GreeterServer < Helloworld::Greeter::Service
  def say_hello(hello_req, _unused_call)
    Helloworld::HelloReply.new(message: "Hello #{hello_req.name}")
  end
end

def main
  s = GRPC::RpcServer.new
  s.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
  s.handle(GreeterServer)
  s.run_till_terminated
end

main

実行

$ ruby server.rb

これでサーバー起動します。

Androidクライアント

適当にプロジェクトを作ります。

build.gradle

プロジェクト直下のbuild.gradleにprotocol bufferのプラグインを追加します。

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
        classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.0"
    }
}

app直下のbuild.gradleにgRPC関連の設定と、protoからコードを生成するための設定を追記します。

apply plugin: 'com.google.protobuf'

// ...

android {

    // Warning:Conflict with dependency 'com.google.code.findbugs:jsr305'.
    // が出たときはこれを追加します
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:2.0.1'
    }
}

dependencies {
    // ...

    compile 'com.squareup.okhttp:okhttp:2.7.5'

    compile 'io.grpc:grpc-okhttp:1.0.2'
    compile 'io.grpc:grpc-protobuf-lite:1.0.2'
    compile 'io.grpc:grpc-stub:1.0.2'
    compile 'javax.annotation:javax.annotation-api:1.2'
}

protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.0.0'
    }
    plugins {
        javalite {
            artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0"
        }
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.0.2'
        }
    }
    generateProtoTasks {
        all().each { task ->
            task.plugins {
                javalite {}
                grpc {
                    option 'lite'
                }
            }
        }
    }
}

protoファイル

app/src/mainprotoディレクトリを作ってそこに、先程作成したhelloworld.protoを配置します。

少し確認した感じですと、protoっていうディレクトリ名が重要でこれを間違えているとうまくビルドできませんでした。

ビルド

ビルドをすると、app/build/generated/source/proto内にソースコードが生成されていると思います。

ソースコード

サーバーとの通信するには、protoファイルから生成されたものを使用して通信します。

newBlockingStubでstubを作ると、処理をブロックして通信が終わるのを待ちます。

// ホストとポートを指定(エミュレータからlocalhostアクセスのために10.0.2.2にしてます)
ManagedChannel channel = ManagedChannelBuilder.forAddress("10.0.2.2", 50051)
        .usePlaintext(true)
        .build();


GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);

// リクエスト生成してパラメータを設定
HelloRequest message = HelloRequest.newBuilder().setName("Android").build();
// 実行して結果を受け取る
HelloReply reply = stub.sayHello(message);

return reply.getMessage();

非同期でやる場合は次のようにnewStubでstubを作って、メソッドを呼び出すときにObserverを渡してあげる感じになります。RxJavaっぽい。

GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel);

HelloRequest message = HelloRequest.newBuilder().setName("Android").build();
stub.sayHello(message, new StreamObserver<HelloReply>() {
    @Override
    public void onNext(HelloReply reply) {
        Log.d(TAG, "Message = " + reply.getMessage());
    }

    @Override
    public void onError(Throwable t) {
    }

    @Override
    public void onCompleted() {
    }
});

iOS

こちらも適当にプロジェクトを作ります。今回はSwiftでやっています。

CocoaPods

CocoaPodsを使いますが、結構特殊な感じになってます。

まずはpodspecを作ります。通常はライブラリ作るときに使うんですけど、protoファイルから生成したコードをライブラリとして設定するためのものになります。

authorsやディレクトリ等の設定は環境に合わせてください。authorsとかはとりあえずサンプルの設定のままやってます。

s.prepare_commandのとこでprotoファイルからソースコードを生成しています。

HelloWorld.podspecとして保存します。

Pod::Spec.new do |s|
  s.name     = "HelloWorld"
  s.version  = "0.0.1"
  s.license  = "New BSD"
  s.authors  = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
  s.homepage = "http://www.grpc.io/"
  s.summary = "HelloWorld example"
  s.source = { :git => 'https://github.com/grpc/grpc.git' }

  s.ios.deployment_target = "10.1"

  # protoファイルのディレクトリ
  src = "../protos"

  # gRPCのプラグイン
  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0"

  pods_root = 'Pods'

  protoc_dir = "#{pods_root}/!ProtoCompiler"
  protoc = "#{protoc_dir}/protoc"
  plugin = "#{pods_root}/!ProtoCompiler-gRPCPlugin/grpc_objective_c_plugin"

  dir = "#{pods_root}/#{s.name}"

  # protoファイルからソースコード生成処理
  s.prepare_command = <<-CMD
    mkdir -p #{dir}
    #{protoc} \
        --plugin=protoc-gen-grpc=#{plugin} \
        --objc_out=#{dir} \
        --grpc_out=#{dir} \
        -I #{src} \
        -I #{protoc_dir} \
        #{src}/helloworld.proto
  CMD

  # 生成されたコードからsubspec設定
  s.subspec "Messages" do |ms|
    ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
    ms.header_mappings_dir = dir
    ms.requires_arc = false
    ms.dependency "Protobuf"
  end

  # 生成されたコードからsubspec設定
  s.subspec "Services" do |ss|
    ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
    ss.header_mappings_dir = dir
    ss.requires_arc = true
    ss.dependency "gRPC-ProtoRPC"
    ss.dependency "#{s.name}/Messages"
  end

  s.pod_target_xcconfig = {
    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
  }
end

Podfileは以下のように自分のディレクトリをライブラリとして読み込むように設定します。

target 'GrpcIos' do
  use_frameworks!

  # HelloWorld.podspec
  pod 'HelloWorld', :path => '.'
end

ここまで出来たらインストールします。

$ pod install

ソースコード

gRPCのコードはObjective-Cになっていますので、Bridging-Headerに使用するものをimportします。

#import <GRPCClient/GRPCCall+ChannelArg.h>
#import <GRPCClient/GRPCCall+Tests.h>
#import <HelloWorld/Helloworld.pbrpc.h>

Swift側のコードimportします。

import HelloWorld

最後に通信する処理を記述します。

let hostAddress = "localhost:50051"

GRPCCall.useInsecureConnections(forHost: hostAddress)
GRPCCall.setUserAgentPrefix("HelloWorld/1.0", forHost: hostAddress)

let client = HLWGreeter(host: hostAddress)
let request = HLWHelloRequest()
request.name = "iOS"
    
client.sayHello(with: request, handler: { (reply: HLWHelloReply?, error: Error?) -> Void in
    if let reply = reply {
        print("message = " + reply.message)
    }
})

まとめ

少し触ってみた感じ使いこなせるとだいぶ強力だなと思いました。型もあって、メソッド呼び出しと変わらないので、JSONより断然扱いやすかったです。

protoファイルによってインターフェースもしっかり定義されるので、それ自体が仕様になるのも良かったです。

敷居は高い感じですが、導入事例も国内外で結構あるようなので今後選択肢に入ってくるのではないでしょうか。

プログラミングしながらできる、健康への近道講座:4回目 - Re.Ra.Ku アドベントカレンダー day 21

こんにちは!
Re.Ra.Kuの泉原です。

ついに4回目、アドベントカレンダーの中では最後の投稿です。
拙い内容でしたが、読んでくださった方々、ありがとうございます!
今回も宜しくお願い致します!

最後は、エンジニアの皆様が最も酷使しているであろう、目・首のストレッチ方法をお伝えします。

目・首の仕組み

今までご紹介した部位に比べて小さい部位である目と首。
小さな筋肉ですが、やっていることはとても大事な働きをしています。

1. 重い頭を支える首

頭の重さは、ご自身の体重の約10%と言われています。
50kgの体重の方の場合、頭の重さはおよそ5kgです。身近なところでいうと、だいたいスイカ1個分ほどの重さです。
日々生活している時は、スイカの重さを首で支えている状態になっています。
1回目で触れたとおり、パソコン業務をしている時は体が前のめりになりやすく、首も前に倒れがちです。
プログラミングしながらできる、健康への近道講座:1回目 - Re.Ra.Ku アドベントカレンダー day 3 - Re.Ra.Ku tech blog
細い首にスイカが乗った状態なので、少し前に倒れるだけでも首にかかる負担は思っている以上に大きくなります。

2. 涙で覆われている目

他の部位は皮膚や筋肉で守られていますが、目は外気に近い部位です。
皮膚や筋肉の代わりに涙で表面を覆って保護しています。
そのため、まばたきが減ったり強い力でこすると、目を守っている涙が乾燥し、目への刺激が強くなり疲れが溜まりやすくなります。
上記に加えて、首の筋肉が固まっていると、目の疲れを取るための流れも悪くなり、目の疲れも取れにくくなります。

目の疲れを取るためにも、首の位置を整えていらない力を抜いてあげる必要があります。

首・目のストレッチ

それではストレッチに入っていきます。
今回もいつもと同じく、1回目の講座で出てきた姿勢を作ってみて下さい。
また、首は背骨を通じて腰・骨盤につながっています。
骨盤周りのストレッチを入念に行ってから首のストレッチをするとよりほぐれやすくなるので、時間がある方は復習してみて下さい。
http://techblog.reraku.co.jp/entry/2016/12/15/150000

綺麗な姿勢を作ったら、左手で椅子の真ん中をつかみ、左肘の裏を表に向けます。
その状態から右手で左耳の後ろを支え、自然な呼吸で右側に体を倒します。 f:id:nozomiii:20161214124337j:plain
気持ち良く伸びたな、と実感できたら息を吸いながらゆっくり体を戻します。
戻した後は反対側も行います。

反対側が終わったら、椅子を持つ位置を真ん中から後ろに変えて、腕の対角線上に体を倒します。
f:id:nozomiii:20161214124308j:plain
これも、気持ちの良い負荷と呼吸で、両方共ストレッチしていきます。

このストレッチは、肩甲骨の回で最初にご紹介したストレッチの応用編からやっていきます。
プログラミングしながらできる、健康への近道講座:2回目 - Re.Ra.Ku アドベントカレンダー day 9 - Re.Ra.Ku tech blog
肩甲骨と首を一緒に伸ばすことができるお得なストレッチなので、ぜひプログラミングの合間にやってみてください。

次に、首と目の疲れを取るストレッチを行います。
首と耳のつけ根のくぼみに親指をあてて、力を抜いて頭の重さで首を後ろに倒します。
f:id:nozomiii:20161214124310j:plain
首の疲れを取ると共に、目の疲れからくるリンパの流れをよくするストレッチです。

最後に、目の疲れを取るストレッチです。
両肘をついて、親指を鼻の付け根の両脇におき、力を抜いて頭の重さで首を前に倒します。
この時、眼球を押さないように、また指の力を最大限に抜くように意識してみてください。
f:id:nozomiii:20161214124330j:plain
考え事をしているついでにできるストレッチなので、ぜひお試しください。

首と目の力が抜けると、自律神経が整い体だけでなく心の疲れも取れやすくなります。
リラックスするとよりコードの進みも良くなると思いますので、ちょっとした合間にやってみてください。

最後に

しつこいようですが、弊社リラクの宣伝もさせて下さい笑
弊社の店舗では首、目、頭もほぐす「アイヘッドケア」というオプションコースもあります。
(一部対象外店舗あり)
10分追加するだけでも、リフレッシュ感が全然違います。
お仕事の合間でも、お休みの日でも、ぜひ試しにいらしてください。
reraku.jp

最後になりますが、4回に渡った今回の企画、読んでくださった皆様本当にありがとうございます!
機会があればまた書きますので、その際はまた宜しくお願いいたします。
今後ともよろしくお願いいたします!