エンジニア的なネタを毎週書くブログ

東京でWebサービスの開発をしています 【英語版やってみました】http://taichiw-e.hatenablog.com/

RESTful APIってなんか意味あんの? って言うタイトルのブログを書こうと思ってるんだけど

うまく言いたいことや考えがまとまらず書く書く詐欺になっているので、ひとまず起こっていること・思っていることを書いてみたいと思います。

起こっていること

シンプルな、データの永続化を行うだけのWeb APIが、リソースの種類ごとにそれぞれ作られています。「ビジネスロジック」はこの中には極力入れないルールになっています。

思っていること

ということは、今作っているAPIは単なる劣化版SQLでしか無いのではないか、というのが昨今の悩みです。

SQL(or RDB)に比べて良くなっている所

  • HTTP故に得られる恩恵があります
    • (使おうと思えば)Varnishなどのキャッシュが使えます
    • ロードバランサーによる負荷分散ができます(でも後ろのDBは結局シングルポイントです)
    • サーバを複数台使用した際の、Service-In や Service-Outが容易です
    • ApacheやNginXなどのWebサーバが持っているアクセスコントロール機能やログ機能が使えます
  • アプリケーションレベルでログが自由にカスタマイズできます

SQL(or RDB)に比べて不便になっている所

  • トランザクションを自力で実装する必要があります。特に、要件上、複数リソースにまたがる原子性が要求されるようなケースでは、

 原子性が破壊されないような仕組みを、Consumerが実装する必要があります。

  • 一般に、HTTPはコネクションのオーバーヘッドが大きいため、DBアクセスに比べて1リクエストあたりの時間がかかります。サービスによっては大きなボトルネックになることがあります。

SQL(or RDB)と変わっていない点

  • ふるまいを記述しないルールなので…
    • Consumerの実装次第では本来許容されないようなデータを作成することが可能です
    • データの使い方が複雑な場合に、Consumerがデータの解釈方法を知る必要があります


…抽象的すぎて、何を書いてるか、自分でもよくわからないなぁ。

Date型をTRUNCするとIndexが効かないよ という話

これ自体は昔から聞いたことがあったのですが、イマイチずっと理由がわかってなくて。

SQLのパフォーマンス問題を引き起こす日付型

単純に、

OptimizerはTRUNCすら何か知らない

というのが原因なんですね。

JavaDayTokyo 2017 Report 2 : Reactive Stream

Reactiveなんちゃらというのがどうもわかりません。

という私が、Pivotalの槙さんのお話を聞いて、随分わかったかも!という気持ちになったセッション。
改めてブログにまとめなおしてみるとやっぱりわかってないところが多々あるのですが、ひとまず忘れないうちにメモを転記します。

発表資料はこちら。
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo

BlockingとNon-Bloking

同期・非同期にかかわらず、基本的にJavaから他のI/O処理を呼び出した場合、レスポンスが返ってくるまでの間、呼び出し元のメインスレッドはお休み中になってしまいます(=Bloking)。
つまり、リソースの無駄遣いが発生するわけですが…

これと対照となるのが、イベントループを用いたNon-Blokingな処理。

イベントループは1スレッドで実行されるため、待ち処理の間に他のリクエストを捌くことができます。

これを実装しているアプリケーションサーバに、Nettyというサーバがあるそうです。
Appleでは35億65万台のNettyサーバが動いてるんだとか…。

Reactive Stream

Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure. ということで、「Reactive Stream」自体はinitiative(=そういう「動き」的なニュアンスなのかな?)らしいのですが

  • non-blocking
  • かつ back pressure
  • な 非同期処理の仕様を策定しよう!

という動きと解釈して良さそうです。

back pressure というのが肝で、Subscriber(データを受け取る方)が、自分の処理能力に合わせて、「これだけちょうだい」って依頼する考え方だそうで。
依頼したあとデータが送られてくるのは非同期な、NonBlockingな処理なのですが、こっちの都合を無視してバンバン投げつけてこられるわけではない という考え方のようです。

Ractor

Reactive Streamの実装としてPivotal社が開発しているのが、Reactor
他に、Reactive StreamとしてはRxJavaが有名ですが、RxJavaはJava6をベースにしているのに対し、ReactorはJava8ベースなのが一つの特徴とのことです。

Spring Framework 5.0でのReactive Spring

従来のSpringMVCはServletをベースにしているため、どうしてもBlockingなアプリケーションになってしまう。そこで、Spring WebFluxと言うものを新たに作りました!

返り値がFluxになっているだけで、従来のControllerと同じように使うことが可能。

その他、String以外のObjectや、Streamを返すことも可能とのこと。
Streamを返した場合、無限ストリームを返すことも可能だそうです。この場合でも、逐次処理なので、OutOfMemoryErrorになるようなことはないそうです。

この、無限ストリームを返す機能と、WebClient(Non blockingなHttpクライアント)を組み合わせると、例えば無限にTwitterのツイートを流し続けるようなアプリケーションも作ることが可能とのこと。

性能比較

リクエストを受けてから1秒Sleepしてレスポンスを返すようなアプリを、SpringMVCとSpring WebFluxで作ってみた場合。

Blockingアプリケーションの場合、1秒のスリープ中はスレッドが遊んでしまうにも関わらず、Blockされてしまうため、上限の200スレッドを超えたリクエストは待ちになってしまいます。

一方、NonBlockingなWebFluxの方は、リクエストごとにスレッドを作るわけではないため、TPSが200以上出ています。

実は、個人的にここ1-2年、よそのAPIを呼んで待ってるだけの、遊んでるスレッドは一つの課題でした。大してリソース食わないけどやたらスレッド数は増えちゃうし、先で詰まっちゃうと釣られて死んじゃう可能性があるし、それを避けるためにはサーキットブレーカーなり何なりが必要になるし…

ということで、発表中にもあったのですが、API Gatewayのような中間に挟まるアプリケーションにはすごく可能性がある話だと感じました!


なお、残念ながら、JDBCには現在Blockingなものしかなく、RDB接続をするアプリケーションの場合、完全にNonBlockingにするのは現時点では不可能、とのことでした。
(Java10で提案はあるそう)



ちょうど今の自分の課題にも関連しそうな技術なので、早めに手を動かしてみて、Updateしたいと思います。

JavaDayTokyo 2017 Report 1 : Java9 関連

今年もJavaDayTokyoに出席させていただきました。この記事ではJava9関連についてまとめます。

Oracle的な目玉はJigsawとjshellでした。

が、

Jigsawは去年のJavaDayTokyoで集中的に話を聞いたけどあまり使いどころがないなぁ… と感じ、
jshellはあると便利だけどこれまた本番で使うようなものではない(あと、以前に触ってみた感じ、そんなに使い勝手いいとも思えない… 変わってるのかな)
ということでこの2つは外して話を聞いてきました。

そんな私に櫻庭さんの、こちらのセッションがドンピシャでした。

D1-A4 Java SE 9のすすめ

Compatibility

いままで一生懸命後方互換性を守り続けてきたJavaがついに一部捨てた… と言うのはすごい分岐点だとは思うのですが、捨てられるだけあって何それなやつは多く。
Java DBってなんや…

Milling Project Coin

Project Coin (Java7に主に取り込まれた、ダイアモンドなど、Javaを書きやすくするプロジェクト)を更にすすめるもの。
Milingがギザギザをつける なので 「『ギザジュウ』作ろうぜ!」的なニュアンスらしいw

StreamAPIで書きにくいよねーっていうのが一部書けるようになった
  • dropWhile
  • takeWhile
  • ofNullable

特にtakeWhileは使いそう。条件満たしたら終了。
これができなくてWhileとか、for + breakが結構残ってる感じ。

Optional
  • stream
  • ifPresentOrElse(action, elseAction)
  • or(supplier)

ifPresentOrElseは使えそうですね。Nullのときの処理をelseとして記述可能に。

CollectionのFactoryメソッド

ofで初期化ができるようになる!

public static final List<String> PLAYERS = List.of("則本", "嶋", "銀次");
public static final MAP<Integer, String> PLAYERS = Map.of(14, "則本", 37, "嶋", 33, "銀次");

もうArrays.asListとか書かなくてよし。
Mapも初期化できるようになったので、何回もputとかしなくてよし。
(テストコードも書きやすくなるんじゃないかなー)

ポイントとして
ofで作ったコレクションはイミュータブル。Javaの標準仕様でイミュータブルなコレクションが扱えるのは初なんだとか。
(これって実装クラスは何が返るんだ? ※あとで確認)

String関係

表立っての変更ではないけど、なかなかおもしろいです。

内部の実装がcharの配列からbyteの配列へ

今までは全ての文字をUTF-16のコードポイント(=16バイト)で表していたのだけど、アスキー文字の場合、8バイトあれば十分なのでbyte型の配列で表すことにした、というもの。
これは結構メモリの使用量変わってくるのでは。
(じゃあ逆に16バイト必要な文字はどう収まるんだろう?byte変数を2個使うのかな? それともそういうときはchar? ※あとで確認)
だったら逆に、サロゲートペアも、もう少し自然に見えるようにしてくれよ… って思ったけど無理か。
 

演算子での結合が StringBuilderに置き換え → invokeDynamicに置き換え

いちいちStrinbBuilderで結合してtoStringする時代が終わるのかしら

で、いつリリース?

今の予定では7月27日… ですが、結局JavaOneのころまでずれるんじゃないの… とのことでした。

今年は、これからド新規でいろいろなものを作っていくので、是非 9 を使いたいところなんですが… 果たして。

読んだ:『伊藤直也氏が語る、マネジメントで本当に大事なのは「問題にフォーカスする」である理由 』

先日、こちらの記事を読みました。
codeiq.jp

ここ二年間の自分と重なる部分が多く、自分に足りなかったところを振り返るきっかけとなりました。

自分とかぶっているところ

私自身は二年と少し前、異動になり、ある開発チームのリーダーになりました。それから、メンバーが「本業」である開発に専念できるような組織づくりをし、技術的負債を解決していくための開発を行ってきました。
一企業のCTOである伊藤さんとは、任されている範囲も責任もまるで違うわけですが、レイヤーは異なるもの、

はじめ組織、そして本丸の技術的負債の解消へ

という流れに共感を抱きました。

技術的負債の解消に対して自分が足りなかったこと

まず自分に足りていなかったこと。

まず行ったのは問題を正しく把握すること。既存の実装と仕様を読んで分析。はやる気持ちを抑えてコードを1カ月ぐらいかけて読み込みました。

私の場合、既存のプロダクトに対する理解/分析にかけたパワーが圧倒的に足りなかったようです。
必死に既存のコードを読んだつもりでいましたが、1ヶ月なんてとんでもなく、せいぜい1週間程度。それも細切れの時間しか使えていなかったように思えます。
結局、自分が読んでいたのは担当プロダクトの一部分。しかも、本当に細かいところまで読み込めていたわけでもなかったため、いざ実装に入ってみると知らない仕様がボロボロ出てきたり、影響範囲の認識が誤っていて後から後から修正対象が広がっていく、ということが起きてしまいました。


そしてもう一点はこちら。

そして、マーチン・ファウラーの著書「エンタープライズ アプリケーションアーキテクチャパターン」で書かれている構造と一休のアーキテクチャと比較し、それをヒントに問題の構造を整理して言語化することを行いました。

私の中には、比較するべき「お手本」がありませんでした。
既存のプロダクトに対するIssueは見極めていたつもりでしたし、それを解決する、「あるべき設計」も自分の中にはあるつもりでした。
ですが所詮それは、独りよがりの、「ぼくのかんがえたさいきょうのアーキテクチャ」止まりだったのだと思います。
それがとんでもなく正解から離れていたとは思いませんが、自分の勉強不足は否めません。

また、自身が勉強不足であるのであれば、こういったときこそ周りの人のもっている知識に頼るべき… だったのですが、積極的にそういったこともしませんでした。


結局、新しいものを作る以前に、現在がどうであるかを正しく理解し、そこに潜んでいる問題を正しく把握する、 そして自分たちが「開発者」として作るべきものを正しく見極める、といったことが全くできていないまま見切り発車し、その後多くの混乱を招くことになってしまったのだと気付かされました。

心理的安全性と責任はセットで考えなければならない

もう一点。記事の順序と前後しますが、この言葉もはっとさせられた言葉です。
実はここ半年程、自身のチームの成長に対して、行き詰まりを感じていました。メンバーの成長ややり甲斐を私がうまく引き出せていない… と思うようになっていたのです。

私が異動した直後のチームは、運用が多くてメンバーが疲弊していたり、ただ言われた実装を淡々としていて技術的な挑戦があまり見られなかったり、 と、エンジニアとして「おもしろくない」環境であるように見えました。
そこで、まずは組織的改革的な方法で運用を減らしたり、ひたすら技術的なチャレンジを組み込めることを見せてみたり ということをまず行いました。
メンバーの「心理的安全性」をはじめに確保するという点で、このアプローチ自体は正しかったと思います。

ですが、その後のステップがあまり良くなかった。

個々のメンバーに「自ら何をすべきか考え」てもらい、そしてそれをチームとして「議論」する、ということをしたかったのですが、そういったチームになっていくためのアプローチが弱く、気がつけば、私がやりたいことをやってもらうチーム になってしまっていたかもしれません(少し極端すぎる言い方ですが)。

もともとはそういった組織を目指していたはずだったのですが、気づけば目の前の問題にばかり追われ、まさに

大事な問題について考えるのが大変だから、ついつい目の前の雑用にばかり目がいってしまう。そして長く大事な問題から目を背け続けていると、事業やプロダクトがわからなくなる。

この状態に陥っていた感がありました。

開発チームに必要なポジションを書き出してみた

今の自分の所属組織の開発フローとか組織わけをベースに、こういう人(役割)がチームに必要だなー というのを書き出してみました。

「攻め」

  • 新しい技術を積極的に開発に取り入れることが可能。

→アンテナが高いことが求められる

  • 圧倒的なコーディング力。開発案件そのものを進める力がある
  • 「良いコード」が書ける。チームメンバーのお手本になれる。
  • 「良いテストコード」が書ける。チームメンバーのお手本になれる。

「和(外)」

  • チーム外に対して必要なコミュニケーションが取れる。質問、交渉、議論。
  • 開発寄りの人たち:インフラ(サーバエンジニア、データベースアドミニストレータ、ネットワークエンジニア)、他の開発チーム
  • 少し外れる人たち:プロダクトマネージャー(スクラムで言うところのPO的な。)、QAチーム

※インフラとか、テスターとか、POとかが同じチームにいたほうが良い、という意見はあるけど、今いる組織では別なのでそれを前提に。
※これより外のステークホルダーとのコミュニケーションはプロダクトマネージャーが担ってくれていて管轄外なので、除外。

「和(内)」

  • チーム内のギロン、モメゴトを良い方向に導ける
  • チームを発展させていくことができる
    • 個々のメンバーの能力を伸ばしていくことが必要なのかな?

※問題の解決には、「攻め」とか「和(外)」とか「運用(改)」が必要なので、本人がこれを持つか、これを持っているチームのメンバーと協力する必要あり。
スクラムで言うところの、スクラムマスターに一番近いと思う

「運用(改)」

  • プロダクトとチームをロングランさせるための方法が考えられる
    • 手作業が多いとか、ログが見づらい などの問題が発見できる
    • 「手作業が多い」はおそらく幅が広い。ちょこちょこデータ更新が必要 みたいな話から、リリースの作業の手間が多い みたいな話とか…
  • (普通レベル):今起こってる問題を見つけ、改善できる
  • (上級レベル):これから起きる問題(まだ本番で稼働していない、開発中のプロダクトとか)に対して問題を見つけ、事前に対処できる

※「攻め」の人と同じか、もっと高度な技術力が要求されることも多いと思う

「キッチリさん」

  • 多少メンドウでもルールを守って物事を進められる人
  • 手順書通り作業できるとか 開発フローを守って開発するとか
  • こういう人がいてくれるとチームが安定する
  • 一方、この手の人におんぶに抱っこになってしまうと人依存になってしまいがち
  • 本人が手を動かすより、風紀委員的なポジションにいてもらったほうが良いんだろうか?

(普通レベル):自分がキッチリできる
(上級レベル):周りが気持ちよくキッチリできる仕組みが整備できる
かも。
※「運用(業)」って名付けようかと思ったけど、この人の幅は運用に留まらない


うむ、自分の中ではなかなかハラオチ。
チームに足りない部分とか、メンバーのキャリアパスとか考えるときの参考になるかも。

何かになぞらえたかったんだけど(RPGの職業とか、野球のポジションとか、星座とか)、いまいちしっくり来るのが思いつかなかったのと、かえってミスリードしそうだから名付けず。

変な順番で出てきてる気もしますが、思いついた順なので、おそらく自分の中で優先順位が高い順なんだと思う。

チームのKPTをちょっとだけ深堀すること

ふりかえりの手法としてKPTはメジャーな方法の一つだと思います。

私がチームでふりかえりする際に、ファシリテータとして少しだけ気を使っている事があります。

KやPは少しだけ掘り下げる

メンバーに意見を挙げてもらうときに、「うすい」意見が出ることが、どうしてもあります。

  • XXが予定通りリースできてよかった
  • YYが難しかった

これだとあまり話が広がらないため、このような意見が出たときは、出してくれた人に問いかけるようにしています。

 

「予定通りリリース亅なら、

「それができた要因ってなんですか?」「どんなところを頑張りました?」

 

「難しい」なら、「どうしてそう感じました?」「何が難しさの原因でした? スキル不足か、知識不足か、周りのせいか…」

 

と、単なる事象の共有だけでなく、その背景にある理由を挙げてもらえるようにします。

挙げてもらったものが、またまた単なる事象の共有の場合もありますので、その際はさらに「その原因は?」ときくようにしています。(いわゆる『ツメている』状況にならない程度に。ここの見極めが難しい)

 

KとPはスコープを広めに

毎回ではないのですがKPTを始める際の枕詞がありまして、

「このスプリントで良かった(or あんまり良くなかった)ことを挙げてください。『自分のこと、チームのこと、プロダクトのこと、環境のこと、何でもいいです』」と言っています。

特に、最後の環境の要因で問題が発生している場合を個人的には重視しています。当人はどうにもならないと思っていても、意外と他の人が聞いたらどうにかなるケースもあり、とりあえず挙げてもらうことが大事だと思っています。

例えば、

PCのスペックが低すぎるとその人は感じているけど変えられないと思っていた。→実は申請すればもっとハイスペックなマシンが使える

的な。

(どうにもならないことも多いので、その際は共感だけして終了です… が、その思いをみんなで共有できる事にも意義はあると思います。)

 

Pを挙げるときにTを考えない

Pを考える際、いきなり解決方法を出してしまうケース多いですよね。

「三回遅刻しました。次から目覚し時計を増やします。」

それで解決できるならいいのですが、何か問題が発生している場合、本人が思いついたTryでは解決できないので問題になっているケースが多いのではないでしょうか。

まず、「遅刻した」と言うのはただの事象なので、先程挙げたとおり、根本的な理由を見つけたいところです。

  • 本人が単に夜更かしして遊んでいたのか
  • 仕事量が多すぎて毎日帰宅が遅いのか
  • 何か心配事があってよく眠れていないのか
  • そもそも遅刻って問題なの?うちフレックス制じゃなかったっけ?

いきなりTryに行ってしまうと、このようにProblemを掘り下げることが難しくなります。

そのため、KやPとを考える時間と、Tを考える時間は分けたほうがいいと思います。