astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

デザイン採用担当はポートフォリオで何を見ているか、何が見えているか?

f:id:astamuse:20161124110530j:plain

初めまして、こんにちは。白木と申します。デザイナーです。

前回、「広告費用を自動取得し100時間分の作業をなくす話 - astamuse Lab」を投稿した後、「白木さんはデザイナーですか?」という趣旨のツッコミを複数からいただきました。その節は大変ありがとうございました。

lab.astamuse.co.jp

私としてはデザイナーが問題解決手段の一つとしてコードを使えることは自然だと考えいます。しかしながら、のっけからその話題だったというのはミスリードでしたね。バランスを取り直すために今日はデザインの話をします。

お題は「デザイン採用担当はポートフォリオで何を見ているか、何が見えているか?」です。

本投稿の目的・狙い

いざポートフォリオを作るとなると悩む方も多数いらっしゃると思います。「どうやって作ればいいのだろう?」「何に気を付ければいいのだろう?」。そういった皆さんの参考になれば幸いです。

またポートフォリオというテーマを通して、デザインで留意すべきエッセンスを書ける範囲でまとめました。おそらくデザイン初心者~中級者の方にも参考になる点があると思います。まずは通読いただいてご自身の知識・経験と照らし合わせて技能の棚卸などにお役立ていただければと思います。

お断り事項

本稿は、誰かとの議論によって得られた結論ではないため、私見の色合いが強いです。これまで見てきた結構な量のポートフォリオと面接を踏まえた属人的価値観といっても差し支えないと思います。その点については予めご了承ください。また、思うところのすべてを書くことは選考管理上できません。従って公開して差し支えない範囲での話ということでご了承願います。

では本題に。

f:id:astamuse:20161124112813j:plain

デザインポートフォリオって?

そもそもポートフォリオとは何でしょうか?ひらたく言えば作品集です。その人が関わってきたプロジェクト、作ってきたものをプレゼンテーションするドキュメントです。ドキュメントという言葉の通り、その媒体としては紙(ないしはPDF)がいまだに主流ではありますが、最近ではWebポートフォリオも少数ながら見かけるようになりました。また、動画を用いたポートフォリオも十分に選択肢に入るような時代になりました。

採用担当者はポートフォリオをどう捉えているのだろうか

まず第一に担当者はポートフォリオをどう捉えているのかを考えてみたいと思います。 ポートフォリオに何を求めているのかと言い換えてもいいでしょう。

これについては概ね以下の側面があると思います。

情報として捉える

単なる「作品の紹介」という捉え方。

応募者がどういったプロジェクト経験があるか、そこでどんな役割を果たしたのか、どんな実務を行ったのかといった情報を伴ったドキュメントです。職務経歴書に近く、純然とした事実情報を伝える機能的な目的で、ポートフォリオの一番ミニマムな要件と言えます。

作品として捉える

次は「ポートフォリオ=作品」という捉え方。

これはポートフォリオの中の個別具体の作品と同じくらいに、ポートフォリオ自体が一つの作品であるという見かたです。 採用担当者にとっては数年前のプロジェクト情報もさることながら、今、目の前にあるポートフォリオの完成度という情報も判断材料になっています。すなわち、ポートフォリオのクオリティが今のその方の力量を表すという考え方ですね。

コミュニケーション機会として捉える

そして三つめはコミュニケーション機会という捉え方。

ちょっとわかりにくいのですが、採用担当者の考え方としては「この応募者はポートフォリオをコミュニケーション機会として捉えられているかな」ということです。

何にしてもそうですが、情報を届けるということは須らく工夫可能なコミュニケーションです。「ポートフォリオを見てもらう」というのも数少ない大事なコミュニケーション機会で、工夫可能なものです。相手が何を欲しているか、自分が何を伝えたいか、それはどのように伝えればスムーズかということを整理し、その上でどうすれば相手がもっと自分のことを知りたいと思ってもらえるかを工夫する。そういったコミュニケーション機会です。

少し余談ですが美術系・デザイン系学校では就活の時(つまり学生時代)にポートフォリオを作成します。自分の就職成功がかかっている重要な位置づけであるため尋常じゃないクオリティのポートフォリオとなることが多々あります。私も学生時代の友人や後輩のポートフォリオを見る機会がありましたが、本当によく考えられているものは「伝え方」「伝える情報」に無理や無駄がなく、それでいてそれを作った本人の魅力を十分に備えていました。「これを作った人はどういう人なんだろう」って思いたくなるような工夫がある。相当に考えたのだろうなぁ、と感動したのを覚えています。

ポートフォリオにはスタイルがある

一口にポートフォリオといっても人によってスタイルが様々です。先ほどご紹介した3側面によってスタイルを分類することもできますが、ここではもっと解りやすいスタイルの違いを2つだけ、その見え方も交えてご紹介します。ご自身のスタイルを再確認できるきっかけになればと。

スタイル事例1「ビジュアル控えめ + 説明多め」

このスタイルは一つの案件に対してやや小ぶりなキャプションが数枚載っており、説明はやや厚め(と言っても200文字もないですが)なことが多いです。一つのポートフォリオにたくさんの案件を掲載する傾向も強い。グラフィック・デザイン能力というよりも数(ないしはその多様さ)とロジカルさでカバーしているタイプ。

見る側からするとグラフィックに自信ないのかなと思われやすいので、もしそうでなければ一枚だけでもいいので「渾身の一作」を入れておくと非常にバランスよく仕上がると思います。あと説明文が多くなってしまったら、ありきたりな記述はばっさり捨てて、エッセンス絞って書くなどの工夫をすると良いです

スタイル事例2「ビジュアル多め + 説明少なめ」

グラフィック・クリエイティブを得意としている方が好まれるやり方です。案件の象徴的なグラフィックを1ページに一個だけさらりと載せて、ワンラインで案件名を書いておしまい。あと余白を配置してすっきりと仕上げるという構成。制作プロダクションにいらっしゃった方が使える見せ方かなと思います。グラフィック得意でない方はやらない方がいいです。

非常に力強く、グラフィックについては申し分ないものが多いです。あとは応募先の会社の業務にそのグラフィック能力をどう転化しうるかを補足的に書くといいと思います。例えばWeb系の会社に応募するのであればWeb案件ものを必ず入れておくなど。DTP系の技能はどこでも重宝するので一つは盛り込んでおいて損はないと思います。

と、ちょっと極端なものを二つ紹介しましたが、載せるもののバランスや見せ方で採用者が窺い知ることはたくさんあります。あなたのポートフォリオを見たときに採用担当者がどう感じるかぜひ想像してみてください。もし客観的な意見を聞きたいのであればあなたが応募したい業界で働いている友人・知人に実際に見てもらうのが良いかと思います。

どんな説明を載せればいいか

次に説明文について整理します。ビジュアル押しのポートフォリオでなければ、だいたい案件ごとに説明を記載することになります。 しかし、実際に書き始めると何を書けばいいのかわからないこともあると思いますので少し噛み砕いていきましょう。

案件内容はベーシックな事項+メリハリ説明文

これは皆さんちゃんとお書きになっているので詳述は割愛します。概ね以下のようなことは基本項目としてさらりと書き、プラスで、どこに付加価値を盛り込もうとしたのかを書くのが良いかと思います。なお書くときは「端的にわかりやすく」を心がけてください。

  1. 案件背景
  2. ターゲットユーザー
  3. クライアントの要求(要件)
  4. 実施・リリース結果

ポートフォリオリオの中でもフィーチャーしたい案件の場合は200文字~くらい書き、それ以外の案件については200文字以下が目安です。繰り返しですが「端的にわかりやすく」。そのうえで魅力を感じさせるように書くと良いと思います。

プロジェクトの日付は絶対に忘れない

意外に無いことが多いのがこの情報です。そして無いと困るのもこれです。年代というのはデザインを評価するうえで一つの基準になります。当時のデザイン的流行、技術的に一般的に可能であった表現の幅、また、その方の年齢がいくつで経験はあったのか。採用担当者はそこも加味しています。これらの算定根拠が日付ですので、きっちり西暦から記載いただけるといいと思います。

担当領域や役割ははっきりと伝わるように

これも皆さんお書きになっていますね。一つ留意されたいのは「UI/UX」など社会通念がまだ確立されておらず、定義・解釈を恣意的にできてしまう場合は、タスク単位で領域を説明することです。面接の段になって「UI/UXって書いてあるけど何してたの?」と聞いた時に回答にばらつきがあり「それはボタンのデザインでは?」ということもあるので。大きく見せることが目的でポートフォリオを作るのでなく、情報としての齟齬をなくしよりミスマッチしないように作るとよいです。

なおNG例はこんな文章。

UI/UXデザイナーとしてユーザーの使いやすさを意識してワイヤーを設計しました。

これを読むと「あたりまえだろ!」となること請け合いです。「せっかくの文字数もったいない・・」と。もっと具体的な話を盛り込むとよいと思います。

全案件を掲載するのはやめよう

ポートフォリオにどれくらいの案件を載せればいいのか。この点についても言及しておきます。 おそらく採用担当者さんは以下の2点からポートフォリオには「全部は載せなくてよい」と考えている方が多いと思います。

  1. 作るのに時間かかりすぎる
  2. 採用担当者もそんなに見れない

全部を載せるために時間かけるなら、もっと伝えるところのクオリティを上げるほうがいいです

正直なところでは、全部載せたポートフォリオ見たら

  1. プレゼンテーションがうまくない
  2. コミュニケーションがうまくない
  3. 自分の能力がわかっていない(強みを理解していない)

と判断すると思います。過去の案件が少なく結果的に全部載せることになったなら話は別ですが。

バランスとしては一番の自信作案件を一点と、能力の深度を示す案件を2,3件、間口の広さを示す案件を2,3件かな、と思います(もちろんそれもご自身でよく考えて欲しいですが)。あとはプライベートで取り組んでいる学習成果を「参考」までに載せておく、と(意外に効果的かも)。

絶対に見えてしまっているところ

ここまでで「ああ、そういう風に見てるのね」というのがお解りいただけたかと思います(全てを話してないのであくまで部分的かと思いますが)。

以降は翻りまして「見えてしまっているところ」についてお話します。たいした驚きはないと思いますが「あ、やっぱり見えてる(見てる)のね」と再確認していただければ。

文字周りは当たり前に見えてしまっている

まずポートフォリオ見ているときにどうしても気になるのが文字です。弊社の場合は文字情報を扱うことが多い仕事ですから、そこへの配慮が欠けているとどうしても気になってしまいます。適切な文字の処理をしないと、読み手に不必要なノイズを与えます。

蛇足かもしれませんが、この点においてはやはり出版系ご出身の方や、制作プロダクションで紙モノをやられていた方が強いように見受けられます。しっかり組まれている。読みやすいのレベルを超えて、美しいと思わせる方も過去いらっしゃいました(願わくばそうなりたいものですね)。

ちなみにどんな点があるのか。以下、いくつかのケースを挙げました。 チェックリスト代わりに使ってみてください。

禁則処理ができているか

句読点などの約物(やくもの)や特定の文字が行頭・行末に出てこないようにすることを禁則処理といいます。これができてなかったら相当がっかりしちゃいます。デザイナーならそこは配慮しようよ、くらいの心持ちです。おそらくイラレがデフォルトで禁則かかっている?から大丈夫だとは思いますが、最終提出の前にもう一度確認してみてください。

f:id:astamuse:20161124125635g:plain

追い出し・追い込みはできているか

禁則処理とセットで意識する項目です。行頭に中途半端な文字がこないように調整することです。ここまで丁寧にできてる人は少ないので、そんなに気にしなくてもよかもしれません。それでも追い出し・追い込みをやってるのを見つけたときは「あ、いいな」って思います。

f:id:astamuse:20161124142345g:plain

文字揃えしているか

複数行にわたる説明文に対しては両端揃えているか。単純に一行の情報が複数箇条書きのようにならぶのであれば必要ないとも思います(ケースバイケースですが)。あと文字揃えという観点でいうと、インデントもチラ見します。例えばこういうケースです。

f:id:astamuse:20161124150402g:plain

ご覧のとおりコロン揃えるようにタブインデントすると綺麗ですね。

行送りに気を付けているか

複数行にまたがる説明文を用いる場合は行送りも自然に気になります。 行送りとは各行のベースライン間の高さを指すもので、「行間調整」といえばわかりやすいでしょうか。 例えば本文なら二分四分アキ(ニブシブアキ) =1.75%が美しいとされています。一方でタイトルテキストは二分四分では少し広いです。ベタ(1.00%)~四部アキ(1.25%)あたりで調整するのがよいかと。

ポートフォリオであればテキスト要素少ないでしょうから主にこの辺りを気にすることになるはずです。

  • タイトル
  • 説明文本文
  • 画像キャプション

この辺りはDTPの基礎的な書籍に概ね書いてあるのでポートフォリオを作るときはぜひご一読ください。また普段読んでいる雑誌にも参考になる要素がたくさんあると思うのでぜひ研究してみてください。

トラッキング、カーニング、字詰め

綺麗にできてたらいいなぁと思います。特に括弧類と句読点はやってあるといいです。イラレはデフォルトのままで出すとがったがたでして、どうしても調整が必要なところです。

f:id:astamuse:20161124152527g:plain

英文と和文のフォントサイズ調整

和文フォントのなかで英文フォントをそのまま使う(「混色」する)と、どうしても英文字が小さく見えます。本文であれば気づきにくいですが、タイトルなどでこれをやるとかなり目につきます。混色を行う場合は英文字のサイズを少し上げて、ベースラインを下げるなどの調整を行います。毎回やるのが面倒という方は合成フォントを利用するのも手です(こちらもちょっと問題あるのですが・・)。

f:id:astamuse:20161124153648g:plain

色周りも見えています

色はそこまで詳しくないので観点が甘いかもしれませんが、下記のようなところは気になっちゃいます。

  1. 文字の色ってどう指定してる?(K=100なのか、K=80なのか、はたまたリッチブラックなのか)
  2. ハレーション起こしてない?
  3. 補色使えてる?
  4. 画面上の色比率どんな感じ?

色にもセオリーがあって、今ではWeb上でも情報は収集できます。ハレーションのようにマナー違反などはちょっと調べればすぐ出てきますので、そういう地雷を踏まないように気を付けましょう。

最後に

以上、お話できる範囲でのトピックを私なりにまとめてみました。 冒頭申し上げた通り、これからポートフォリオを作ろうとされている方の参考になれば幸いです。またこれを読んだ方のデザインの勉強のきっかけになればいいなと。

それにしても、ポートフォリオは作ろうと思って実際にできるまでそれなりに時間がかかります。いざ作ろうと思っても素材から採取せねばならないので手間なんですね。 そこでこれをご覧になられた方は、定期的に自分が関わってきたサービスなりプロダクトの写真やキャプション画像を保管しておくことを強くおすすめします。ポートフォリオ作ろうとおもったらそのサービスなくなってて(リニューアルされてて)キャプションとれないことが非常に多いですし、ポートフォリオ作る作らないにかかわらず過去の記録を残すと自分の成長を実感して前に進む原動力になるので。

そして、そのポートフォリオを持ってぜひ私たちの会社の選考を受けに来てください。 こんな偉そうに書いてますがまだまだ全然道半ばなので、一緒に成長してデザインのクオリティを上げてくれる仲間を心よりお待ちしております!

最近リニューアルした採用サイト↓ recruit.astamuse.co.jp

【資料公開】Cloudera World Tokyo 2016 で登壇しました。

こんにちは。アスタミューゼ開発・インフラ部の福田です。

11月8日に開催された Cloudera World Tokyo 2016 にて登壇させていただきました。

こちらが、当日の資料になります。

セッションについて

『HBaseで実現する大量の特許文書データを扱うためのアーキテクチャとベストプラクティス』

というタイトルで、

アスタミューゼでの取り組みのほんの一部ではありますが、astamuse.comで公開している 大量の特許文書データとその周辺を、Hadoop、HBaseの使用事例としてお話させていただきました。

今回、このような貴重な機会を下さったCloudera社の皆様、セッションを聴きに来て下さった皆様に心から感謝しております。

ありがとうございました。

Special Thanks To

  • イラストを使用させていただいたいらすとやさん
  • 最後にスライドのお化粧をしてくださったアスタミューゼデザイン部のMatsumotoさん
  • 渋皮栗のモンブランが売り切れでも嫌な顔一つせず相談にのってくださった並河さん
  • 発表の準備を厳しい目で支えてくださったアスタミューゼ開発メンバーの皆さん
  • MacBookを開いて長時間ひとりでぶつぶつ言う私をそっとしておいてくれたカフェの店員さん

ありがとうございました。

Java8になってから開発者は色々と楽になった、のだろうか?Spring BootでWebアプリを作って検証してみた

どうもえいやです。今回の技術ブログを担当します。

前回はGebの話をしました。皆もうブラウザテストは自動化出来たかな。

今回は、前回と変わって当社のWebアプリケーションのバックエンド開発言語となっているJavaの話です。

ラムダ式使ってる?

Java8がリリースされてずいぶんと経ちますが、皆さんの現場ではJava8の力はちゃんと発揮されているでしょうか。

先日、同僚が出かけたJavaのイベントでは、講演者が参加者に向けて、「Lambda式を使っている人は手を上げてみてください」と求めて見たところ、ほとんど手が上がらなかったそうです。

当社では、エンジニアは全員Scalaが書けるということになっていますので、Javaの案件でも特に違和感(Scalaのそれに比べ、少し(?)不便なのは置いといて)なく使えているんですがねぇ。。。

とまれ、Java8では、それまでのJava7から、言語仕様の面などで色々とちゃんと使えば便利になるはずのものがたくさん追加されています。

今回の内容

今回は、Java8で追加された言語仕様を極力多用する形で、ある程度業務レベルの仕様を想定したサンプル・Webアプリケーションを0からスクラッチで書いてみるということをしてみました。

目的は、Java8の主に言語仕様とその仕様を用いることを想定した新規のライブラリおよび機能を使いこなすことで、Web開発での利用において(RubyOnRailsなどに比べ)生産性が悪いと言われているJavaの問題を少しくらい払拭できるのかを検証してみることです。

なお、当社では普段のWeb開発のフレームワークには、自社製のAsta4Dを使用していますが、今回は使用者が多いと思われるSpring Bootを用いました。

結論から言うと、スクラッチ開発が楽になるものではないな、ということでした。完成してませんもん。

話はそれまでなのですが、続きを読みたい方は以下続きます。

せっかくなので、今回作る際にどんな感じでLambda式などの仕組みが出てきたのかとかも解説します。

Java8だからといって、何が楽にならないのか

比較対象として、GroovyのRails実装であるGrailsについて見てみると、Grailsで2日で出来たことが、今回の検証では(真面目に実装をやり始めて)4日経ってもまだ半分しか完成していません。

比較対象にGrailsを選んだ理由は、仕組みは大体わかっているが普段の仕事ではあまり使ってない、というWebフレームワークだからです。

Grailsは実は今回使用したSprinng Bootを土台に、上にRailsの実装を施して楽に開発出来るようにしたようなものなので、最低限使える程度のテンプレートやORMの仕組みなどを自分で追加しなければならないJava+Spring Bootで想定するスクラッチ開発とはスタート地点が異なります。

そういう意味では比較対象としてはふさわしくはないのですが、改めてJavaのWeb開発において一般的に言われている生産性を阻害する点を実感したところです。

Java+Spring Bootでスクラッチ開発をやろうとなったとき、実際のところ5割以上の時間を費やすのがこの開発を開始するための土台作りです。

Railsなどではこの土台が既に出来ており、しかも大体の場合、自分で作った土台より遥かに出来が良い状態から始まるのです。

土台作りに慣れていて、ある程度分かっていたとしても、以前使ったことのあるものがバージョンアップされていたりすると、妙なところでハマったりしてなかなか険しい道のりです。

今回は普段の開発でも似た仕組みを持っていて、ある程度手慣れている部分でも大ハマリしてしまいました。

こんななので、秘伝のタレのような、一度に大きな変更や更新をしてはいけないFW設定を持つチームも多いでしょう。

こうした部分は、もはや言語の問題ではないので(JavaでGrailsを使うことも出来る)今回の検証の仕方が悪かったかなという気がしなくもないです。

と言っても、僕の想像している範囲では、Javaの開発って保守と改修以外ではいっつもココから始めてるよなぁという印象です。

この辺が楽にならないと新規の開発は永遠に楽にならないと思います。

本題の検証用Webアプリケーション

さて、今回検証用に作った(作りかけですが)Webアプリケーションはさらっとした感じでは以下のようなものです。

f:id:astamuse:20161115200417p:plain

使用する技術、アーキテクチャとしては以下となります。

f:id:astamuse:20161115200403p:plain

Spring FWには、Spring Bootはじめ色々と含まれていますが、まとめて箱にいれました。あとでソース置いてあるところ示しますので、build.gradleをみて確認しておいてください。

ビルドにはGradleを使いました。Spring Bootの起動には、Grettyプラグインを使用します。

年齢の制限などを加えている部分は、対象のコンテンツかどうかAOPで検出します。この際にはAspectJ形式のアノテーションを利用します。

設定に関しては、Javaコードで書くことがメインなのでXMLを用いずにJavaで設定を書くことにしています。

その他HTMLテンプレートとしてthymeleaf、フロントエンドの実装のためにBootstrapjQueryを使用しました。

フロントで複雑なことはしないので、このあたりのことには触れません。とはいえ、(サーバサイドのエンジニアなりに)ちゃんとやった感がでるくらいには頑張りました。

んで、見た目はほとんどBootstrap頼りで以下みたいな感じにします。

f:id:astamuse:20161115200427p:plain

(作りかけの)コード

さて、どんな感じに設計しているとかは置いといて、作りかけですが、コードをGithubに上げておきます。試行錯誤の後があまりに汚ないので、リポジトリにログは残していない形です。

github.com

作りかけではありますが、一応起動できる状態ですので、ためしに動かしたければどうぞ、つってもアカウントの登録の時点で動いてないんだけどね。

この記事までに完成を間に合わせたかったのですが、土台をイチから作っていると、色々なところでハマるので間に合っていません。ただ、記事には出来るように、普段の作り方とは逆で、実装が面倒そう、Java8の力が発揮できそうな部分から作って行ったので、コードとしての完成度はそれなりにあります。

今回は完成させるのが目的ではなかったので、検証結果は「やっぱり大変なことに変わりない」ということで良いと思います。

では、この作りかけの-一応動くところは意図通りに動いている-コードをもとに、Lambda式などのJava8になってから追加されたコードがどのように現れてくるのか、使った意図の説明を交えて見ていきましょう。

Lambda式の使用ポイント その1 その場その場でコードを快適に書く設計

一つのファイルのコードにおいて一番Lambda式が目立つのは、

jp.eiya.aya.web.util.security.PermissionManager

でしょう。以下のような感じです。

public class PermissionManager extends AbstractPermissionManager {
    public static final class Permissions{
        public static final String NOT_LOGIN_SESSION = "notLoginSession";
        public static final String HAS_ACTIVE_LOGIN_SESSION = "hasActiveLoginSession";
        public static final String HAS_PAID_TICKET = "hasPaidTicket_computed";
        public static final String ACCOUNT_INFO_IS_COMPLETED = "accountInfoIsCompleted";
        public static final String OVER_18_AND_MORE = "over18AndMore";
        public static final String UNDER_18_LESS = "under18Less";
        public static final String OVER_20_AND_MORE = "over20AndMore";
    }

    @Named(Permissions.HAS_ACTIVE_LOGIN_SESSION)
    public Permission hasActiveLoginSession() {
        return () -> loginService.getLoginUser().isPresent();
    }

    @Named(Permissions.NOT_LOGIN_SESSION)
    public Permission notLoginSession()  { return ()-> !hasActiveLoginSession().isGranted(); }

    @Named(Permissions.HAS_PAID_TICKET)
    public Permission hasPaidTicket() {
        return () ->
            checkIfPresent(
                loginService.getLoginUser(),
                (loginUser) ->
                    paymentService.getPaymentStatuses(loginUser).stream()
                    .filter(PaymentStatus::hasPaidTicket_computed)
                    .findAny()
                    .isPresent()
            );
    }

    @Named(Permissions.ACCOUNT_INFO_IS_COMPLETED)
    public Permission accountInfoIsCompleted() {
        return () ->
            checkIfPresent(
                loginService.getLoginUser(),
                (loginUser)->accountInfoService.getAccountInfo(loginUser).isCompleted_computed()
            );
    }

    @Named(Permissions.OVER_18_AND_MORE)
    public Permission over18AndMore() {
        return () ->
            checkIfPresent(
                loginService.getLoginUser(),
                (loginUser)->
                    checkIfPresent(accountInfoService.getAccountInfo(loginUser).getAge_computed(),
                    (age) -> age >= 18
                )
            );
    }

    @Named(Permissions.UNDER_18_LESS)
    public Permission under18Less() {
        return () ->
            checkIfPresent(
                loginService.getLoginUser(),
                (loginUser)->
                    checkIfPresent(accountInfoService.getAccountInfo(loginUser).getAge_computed(),
                    (age) -> age < 18
                )
            );
    }

    @Named(Permissions.OVER_20_AND_MORE)
    public Permission over20AndMore() {
        return () ->
            checkIfPresent(
                loginService.getLoginUser(),
                (loginUser)->
                    checkIfPresent(accountInfoService.getAccountInfo(loginUser).getAge_computed(),
                    (age) -> age >= 20
                )
            );
    }
}

このクラスは、前述のアカウント情報について、年齢、課金の状態などを元に、指定した状況とユーザーの持つ状況を比較してコンテンツを見ることが出来るかどうかのPermissionを定義しています。

別のAOPの実装との兼ね合いでやや冗長な@Namedの指定になっていますし、本当はそれぞれのメソッド呼び出しが複数回起きないようにすべきですが、気にしないでください。

さて、このコードがこんなにLambda式だらけに出来るのは、親クラスであるAbstractPermissionManagerにて、次の内部インターフェースが定義されているからです。

    /**
     * provide a permission has the way to check it is granted.
     **/
    public interface Permission {
        boolean isGranted();
    }

    /***
     * check the opt if it's present,else returns false
     */
    protected <T> boolean checkIfPresent(Optional<T> opt, Check<T> check){
        if(!opt.isPresent()){return false;}
        return check.check(opt.get());
    }

    protected interface Check<T>{ boolean check(T obj); }

上記で定義されている、Permission,Checkのように、一組の引数の型と数について一つだけメソッドが定義されているインターフェースは、そのインターフェースをLambda式によって実装を記述し、無名クラス(匿名クラス)として初期化出来ます。

特にCheckprotected boolean checkIfPresent(Optional opt, Check check)の引数です。なお、このメソッドは、与えられたOptionalが値を持つときのみ、その値を引数Checkのメソッドboolean check(T obj)で評価して返します。値がないときはfalseを返します。

なお、このOptionalもJava8から使えるようになった機能です。主に結果があるかどうかが不明なメソッドの返り値の型として利用します。うまく使うとNullチェックを減らしたり、NullPointerExceptionを減らしたり出来ます。

さて、上記のインターフェースについて、ネストが深めのover18AndMore()で使用例を見てみましょう。

    public Permission over18AndMore() {
        return () ->
            checkIfPresent(
                loginService.getLoginUser(),
                (loginUser)->
                    checkIfPresent(accountInfoService.getAccountInfo(loginUser).getAge_computed(),
                    (age) -> age >= 18
                )
            );
    }

over18AndMoreの返却値の型はPermissionです。

ですので、このメソッドの戻り値はLambda式で実装できます。

Lambda式では、式が一行で示される場合、ブロックステートメント{}を省略し、returnも記述不要です。

このメソッドの返り値である無名のPermissionの実装のLambda式はちょうど式が一行で、その式はcheckIfPresentメソッドの呼び出しです。

checkIfPresentの第2引数はCheckなので、これもLambda式で実装されています。

第一引数のOptionalに中身があったときのみ、その評価が行われます。この評価の中で、Optionalが返ってくるメソッドの呼び出し、AccountInfo.getAge_computed()があり、その評価もまたcheckIfPresentを使って、最終的には18才以上なのかをチェックした値が返されます。

この2つのInterfaceとメソッドの定義により、実装の中ではif文はでてきません。

こうした記述方法のメリットは、かなりコードが短くなることです。また、メソッドに名前がついているのでifと評価式で書かれるより、やっている内容がひと目でわかります。

似たような例は、jp.eiya.aya.web.dao.base.UpdateQueryRunnerにもみつけることが出来ます。

ただ、このような実装は、これまでにInterfaceが持っていた、あるメソッドが実装されていることを保証し、再利用性を高めるという役割とやや違っていて、いくらか場当たり的な実装のための手段のように見えます。

なので、この事例のように、interfaceをprotectedやprivateのような狭いスコープに閉じ込めておいたほうが良いでしょう。

Lambda式の使用ポイント その2 後のことを楽にする仕組みの設計

こっちの使用ポイントでは、先ほどと違ってLambdaで実装を記述できるInterfaceを広いスコープ、publicに開放します。

このインターフェースは、jp.eiya.aya.web.util.rest.APIResponseです。

定義はこんなです。

package jp.eiya.aya.web.util.rest;

public interface APIResponse<T> extends ContentResult<T>{
    default boolean success() {return true;}
    default String message(){return "request finished successfully.";}

    static <T> APIResponse<T> failBy(String message,ContentResult<T> contentResult){
        return new APIResponse<T>() {
            public boolean success(){ return false;}
            public String message(){ return message;}
            public T getResult() { return contentResult.getResult();}
        };
    }
}

public interface ContentResult<T> {
    T getResult();
}

このインターフェースは、ResponseBodyとして戻されることを意図しています。デフォルトでは成功を示し、failByによって戻される無名のAPIResponseは失敗を意味します。

インターフェースに対し、デフォルトでは、という使い方ができるのは、これもJava8で新たに登場したインターフェースに実装を書けるdefault methodの仕組みのおかげです。default boolean success() {return true;}の部分がこれに当たります。

さて、これらの使い所はこんな感じ。会員登録のフォームをPOSTしたときのコントローラの振る舞いです。

    @RequestMapping(method = RequestMethod.POST)
    public @ResponseBody APIResponse<RegisterForm> register(@RequestBody RegisterForm form) {
        return tx.execute(status ->{
            boolean success = accountService.create(form.getAccountName(), form.getPassword());
            if (success) {
                Optional<Account> account = accountService.getAccount(form.getAccountName());
                if (account.isPresent()) {
                    success = accountInfoService.upsert(account.get(), ImmutableMap.of(
                            AccountInfo.FIELD_USER_NAME, form.getUserName(),
                            AccountInfo.FIELD_DISPLAY_NAME, form.getDisplayName()
                    ));
                }
            }
            if(!success){
                status.setRollbackOnly();
            }
            return success;
        }) ? () -> form:
             APIResponse.failBy("fail to registration", () -> form);
    }

tx.executeはトランザクションの実行です。これに引数として与えているのもLambda式ですが、これは気にしないでください。

APIResponseの使われどころは、

return success ? () -> form:
                 APIResponse.failBy("fail to registration", () -> form);

この部分です。

これだけで、APIの戻り値として機能する(具体的にはエラーメッセージがヘッダーに入ったりする)型に変換されるようになります。(そのResponseのコンバータの実装終わってたっけかなぁ。。。)

これを行うことでフロントエンド側で幸せな事態を起こすことが出来ます。

このように、後のほうでお約束の書き方を取り入れて便利にしてあげるという仕組みづくりに使うことが出来ます。

問題は、スコープが広いのと、引数になんでも入れられる弱い型制限を取るため間違った使い方を起こしやすいことです。こうした仕組みを作った場合は、どういう目的のために使うのかチームでちゃんとお約束事の勉強をしましょう。

まとめ

  • JavaのWeb開発を最初から始めようとすると、時間がかかる部分は言語の問題ではなさそう。

  • 実装の面ではJava8になってからあらたな書き方、設計が出来る様になった。それは、使い方しだいでは開発を楽にしてくれる。

さて、今回はLambda式の使い所を軽く紹介した程度ですが、実装の面では他にもJava8から追加された色々な機能の恩恵をふんだんに受けています。

それは普段の開発でも同じで、過去の部分を改修する際にはよりエレガントなコードを(これまでよりは)書けるようになっています。

繰り返してきたように、やはりJavaのWeb開発で大変なのは、土台作りの時点だなぁと思いました。

この部分がどうにかなるようなものってのは、なんかJavaの文化を合わないのかもなぁ(Grails流行らないし)とも思いつつ今回はココまで。

どうも、ありがとうございました。


P.S.今回のコード、まともに動くものではありませんが、中身を読んで、ココはこうした方がいいよとかご意見いただけるとありがたいです。

※ ドキュメント中のフォント・・・ゆたぽん (コーディング) フォント (http://net2.system.to/pc/font.html)

P.S.Kotlinでも楽になるのか検証してみました。

Copyright © astamuse company, ltd. all rights reserved.