コネヒト開発者ブログ

コネヒト開発者ブログ

もしDHHさんがCakePHPのコントローラーを書いたら

f:id:itosho525:20170601124347p:plain

こんにちは!乃木坂46の西野七瀬さんと誕生日が同じサーバーサイドエンジニアの@itoshoです。

僕は元々PHPerなのですが、ここ1〜2年くらいRubyを書く機会が多かったこともあり、最近はRubyでいいな!と思った考え方や技術をPHPに輸入することにハマっています。

そこで今日は少し古い記事になるのですが DHHはどのようにRailsのコントローラを書くのか を参考にして、Ruby on Rails(以下Rails)の産みの親であるDHHさんのコントローラーの書き方をCakePHPに取り入れてみたいと思います。

DHHさんのコントローラーの書き方

そこに至るまでの考えなどの詳細は元記事をご覧いただければと思いますが、要約すると、

RESTの原則に従う場合、コントローラはデフォルトのCRUDアクションだけを使い、その他のアクションは新たに専用のコントローラを作成する。

という考え方になります。

DHHさん流コントローラーのメリット

基本的には以下の2つがメリットになるかと思います。

  • コントローラーがスリムになる
    • フルスタックなMVCフレームワークは往々にしてコントローラーがファットになりがちですが、デフォルトのCRUDアクションのみを利用するため、ファットコントローラーを構造的に防止することが出来ます。
  • ルーティングのルールが明確になる
    • カスタムアクションの命名規則が開発者によってバラバラになったり、そもそもそれを防止するための命名規則のガイドラインを作成したりするコストがなくなるので、ルーティングの設計コストを下げることが出来ます。

DHHさんの考えをCakePHPに適用してみる

では、早速DHHさんになりきって、CakePHPのコントローラーを書いていきましょう。 例として、元記事にもあったメールの受信箱を管理するコントローラを書いてみたいと思います。 尚、CakePHPのバージョンは3.4系を利用しており、サンプルコードのためphpDocumentorの記述などは省略しています。

コントローラークラス編

まず、デフォルトのCRUDアクションを持つコントローラークラスを書いていきます。

<?php

namespace App\Controller;

class InboxesController extends AppController
{
    public function index()
    {
        // 一覧を取得する処理
    }

    public function view($id = null)
    {
        // 詳細を取得する処理
    }

    public function add()
    {
        // 新規追加する処理
    }

    public function edit($id = null)
    {
        // 更新する処理
    }

    public function delete($id)
    {
        // 削除する処理
    }
}

Railsのデフォルトアクションは index, show, new, edit, create, update, destroy ですが、CakePHPの場合は index, view, add, edit, delete になります。

ここで新たに未送信のメール一覧が閲覧できる機能を追加しようとなった場合、よくやる実装としては、以下のようなアクションをInboxesControllerに追加するやり方ではないでしょうか。

<?php

public function pendings()
{
    // 未送信の一覧を表示する処理
}

もちろん index アクション内で出し分けるというやり方もあると思いますが、新しいアクションを追加するというアイディア自体はそれほどおかしいものではないと思います。

しかし、DHHさんはこの場合、新しいアクションではなく、以下のような新しいコントローラークラスを作成します。

<?php

namespace App\Controller\Inboxes;

use App\Controller\AppController;

class PendingsController extends AppController
{
    public function index()
    {
        // 未送信の一覧を取得する処理
    }
}

namespace App\Controller\Inboxes でサブリソースのような形で名前空間を切り、その中にコントローラークラスを作成して、デフォルトのCRUDアクションである index アクションを定義します。 ちなみに PendingsController はControllerディレクトリ内にInboxesディレクトリを作成して、その配下に格納しています。

ルーティング編

コントローラークラスが出来たので、次はルーティングの設定を行います。 今回は以下のようなREST的なルーティングが出来るようにしたいと思います。

HTTPメソッド URL 対応するコントローラアクション
GET /inboxes InboxesController::index()
GET /inboxes/123 InboxesController::view(123)
POST /inboxes InboxesController::add()
PUT(PATCH) /inboxes/123 InboxesController::edit(123)
DELETE /inboxes/123 InboxesController::delete(123)
GET /inboxes/pendings PendingsController::index()

このルーティングを実現するには routes.php 内で、

<?php

$routes->connect(
    '/inboxes',
    ['controller' => 'Inboxes', 'action' => 'index', '_method' => 'GET']
);

のようなナイーブな書き方をアクション毎に定義することでも実現出来るのですが、CakePHPでは以下のように書き方でもっとシンプルに定義することが出来ます。

<?php

$routes->resources('Inboxes');
Router::prefix('inboxes', [], function ($routes) {
    $routes->resources('Pendings');
});

このようにシンプルに書けるのもRESTに沿ったデフォルトのアクションを利用しているお陰かなと思います。

以上でDHHさん流コントローラーの完成です!

まとめ

もちろん、このやり方が全てのWebアプリケーションにとっての銀の弾丸にはなり得ませんし、RailsとCakePHPでは考え方が異なる部分もあるので、DHHさんがやっているから!という理由だけで導入するのは危険だと思います。 とは言え、少なくともRESTベースなWebAPIの開発などでは、このルールを導入するメリットはとても大きいのではないかと個人的には感じているので、これから積極的に導入していければなと考えています。

そして、PHP vs Rubyみたいな不毛な宗教戦争はやめて、今後もお互いの言語のよいところを取り入れながら、よりよいプロダクトつくっていきたいと思う次第であります。

参考サイト

jeromedalbert.com postd.cc tech.kitchhike.com qiita.com

CakePHP3.4.7にアップデートしました!

f:id:itosho525:20170430222524j:plain

こんにちは。 ℃-uteが解散してしまうのが哀しくてたまらないサーバーサイドエンジニアの@itoshoです。ちなみに℃-uteでは鈴木愛理さんが好きです。

この連載も3回目になります!今回も簡単にアップデート内容をまとめさせていただきました。

CakePHP3.4.7の変更点まとめ

今回は以下の変更がありました。

  • 非推奨メソッド用にAPIドキュメントの改善
  • メッセージがcontextと空文字の両方を持っている場合はTranslatorクラスはキー名を返却するように修正
  • ネストされたリクエストボティのパラメーターがOauth1のクライアント認証アダプターでエラーとなる不具合を修正
  • IntegrationTestCase::enableRetainFlashMessages() 関数の追加
    • assertSession()関数を利用してフラッシュメッセージをアサート出来るようです。
  • Validation::hexColor()関数の追加
  • ネストされたmatching()関数をコールするページネーションクエリが無効なSQLを発行する不具合を修正

詳細は公式のリリースノートをご覧ください。

アップデート時にやったこと

今回も軽微な変更のみだったので、composer updateコマンドを実行後、CIが通っていればOKとして、リリースを行いました。 (リリース後も特に問題は発生しておりません)

おわりに

CakePHPのアップデートが続く限り、このブログは解散しませんので、引き続きよろしくお願いいたします。

JavaScript(React+Flux)のディレクトリ構成がガタガタになりそうだったので反省して改善する

f:id:dachi023:20170524174143p:plain

こんにちは。フロントエンジニアの@ry0_adachiです。

ここのところ、React + Flux Utils *1 の構成を選択することが多く、それ以外を選択することが少なくなってきました。特に大きな不満はないし、慣れてきたので良いかもな〜と思っていたのですが、開発期間が伸びてきて、アプリ自体の規模がそこそこになってくるとFacebook公式のサンプルコードのようにシンプルな構成だけではカバーしきれない状況が生まれることもあります。運用し始めてだんだんとその辺の辛さみたいなものが見えてきたのと、継ぎ接ぎな構成になるのは嫌だったので、このタイミングで1回整理して改善してみようと思いました。

Fluxについて

Facebook提唱のアーキテクチャ、またはフレームワークです。データの流れを一方向にして、シンプルに状態管理が行えることがメリットとしてよく挙げられています。Fluxについてより詳しく知りたい方は以前書いた記事があるので良ければそちらも合わせて読んでみてください。

f:id:dachi023:20170523163305p:plain GitHub - facebook/flux: Application Architecture for Building User Interfaces

本題に入る前に

GitHubで参考になりそうなFlux Utils製のアプリケーションのディレクトリやファイルの構成を見ていると各プロジェクトに最適化されている(しようとしている)ものが多く、参考になる部分とならない部分があります。この辺はフレームワーク側で制限しない限り、それぞれが使いやすいものが生まれ続けるでしょう *2 。この記事の内容についてもハマるものもあるだろうしハマらないものもあるはずなので、こうした方が良い!というわけではなくて、あくまで参考程度に捉えてもらえると幸いです。

最初に考えた構成

最初に作り始めた時は公式のサンプルコードにあったチャットアプリをベースにして、そのあと最低限必要なものだけを足して下記の図のような構成にしました。

チャットアプリ *3 : flux/examples/flux-chat at 3.1.0 · facebook/flux · GitHub

js-root/
  ├ actions/
  │   ├ api/
  │   │   └ TodoApi.js
  │   └ TodoActions.js
  │
  ├ components/
  │   ├ TodoList.js
  │   └ TodoListItem.js
  │
  ├ constants/
  │   └ ActionTypes.js
  │
  ├ containers/
  │   └ AppContainer.js
  │
  ├ dispatcher/    
  │   └ AppDispatcher.js
  │
  ├ stores/
  │   ├ TodoStore.js
  │   └ records/
  │       └ Todo.js
  │
  └ utils/
  • 補足1. CSSは別ファイルに出力、別で読み込んでいるのでこの図では考慮しない
  • 補足2. ActionCreatorにAPIコールの責務を持たせるのでactions/api/を作成する
  • 補足3. APIクライアント以外で各レイヤーに収まらないものはutils/に集約する

この構成にして反省したこと

役割を階層で表現できていると思っていた

actions/api/が悪い例で、下記が理由です。

  1. ActionCreator以外からは呼んではいけません、を階層で表現しようとしていた
  2. 呼んではいけなさそうだな!という雰囲気を醸しているだけで呼ぼうと思えば呼べる

ガチガチにやるなら、チェックツールなどで「Action以外がAPIクライアントのメソッドをコールしているか」といった処理をするべきで、わざわざディレクトリの構造を複雑にしてまでやることではありませんでした。今は普通にコーディング規約として文字に起こしてチームメンバーに共有しておく、くらいで良いかなと思います。

Componentの中でのレイアウトとコンポーネントの切り分け

Componentの種類を「パーツを組み合わせたもの」と「パーツ」の2つではっきり分けるべきでした。参考にしていた公式のサンプルコードにはMessageSection.react.jsThreadSection.react.jsがComponentとして用意されていて、こういう風にすれば良かったのかと後から気づきました。

共通で使えるComponentなのかどうかが分からない

components/に置かれたものが「プロジェクト全体で共通的に使えるもの」なのか「特定の画面のみで使われるもの」なのかの判断をぱっと見で付けられなくなってしまったのでもう1つディレクトリを切ったほうがよかったです。

より実用的なディレクトリ構成を考える

反省点を改善できるように修正をしたのが下記の図になります。

js-root/
  ├ actions/
  │   └ TodoActions.js
  │
  ├ components/
  │   ├ common/
  │   │   ├ TextField.js
  │   │   └ Button.js
  │   └ todo/
  │       ├ Section.js
  │       ├ TodoList.js
  │       └ TodoListItem.js
  │
  ├ constants/
  │   └ ActionTypes.js
  │
  ├ containers/
  │   └ AppContainer.js
  │
  ├ dispatcher/    
  │   └ AppDispatcher.js
  │
  ├ stores/
  │   ├ TodoStore.js
  │   └ records/
  │       └ Todo.js
  │
  └ utils/
      └ api/
          └ TodoApi.js

改善されたこと

actionsの中はActionCreatorだけになった

actions/api/utils/api/にしたのでactions/にはActionCreatorだけが入ることになりました。API関連はActionCreatorから切り出されたような形になったので、例えばAPIクライアントを別パッケージにします〜となった場合でも切り出すイメージが湧きやすいかもなぁ、とそんなことも思いつきました。

ComponentにSectionを設ける

Sectionを設けたことでレイアウトやパーツの集合体を定義するクラスが明確になり迷うことがなくなりました。Sectionがレイアウトやパーツの集合体でそれ以外はただのパーツである、という認識をしっかり持てたことで前に比べるとチーム開発もしやすくなったかもしれません(今は私1人でJS書いてるのでまだ試してませんが…)。

共通なComponentとそうでないものはディレクトリを分ける

プロジェクト内で使い回しの効くComponentを切り出したことで「前にこんなの作ったけ?」と考える時間が減ったのと、共通化しようという意図が見えやすくなりました。この辺はUIを考えてくれているデザイナーさんに相談しながら少しずつ共通化して切り出していくようにしています。

余談ですが、Componentが共通化される条件は「ロジック的に使い回せるか?」よりも「UIとして使い回せるか?」を判断軸にしています。これは、CSSとComponentの組み方の乖離 *4 が大きくなると実装が後々大変になるだろう、と判断してそうしています。

まとめ

事前に想定できるケースを洗い出しておくのは前提として、最初に決めた構成のまま突き進むのではなく状況に合わせて適宜変更していく・変更しやすい状態を保つことが重要です。また、途中で開発チームの規模が大きくなるかもしれないので複数人でも開発しやすい状態などを考慮しておくことも重要です。開発者が考える時間を減らしてあげることは開発効率の向上にも繋がるのでしっかりとメンテナンスしていきたいですね。

脚注

*1:Flux UtilsはFluxのリポジトリ(facebook/flux)に含まれています。

*2:現状は決定版となる構成が特にない状況だと認識しています。

*3:2017/05/25: masterにはなかったので3.1.0のタグから引っ張ってきています。

*4:CSSは共通化しているのにComponentはされていない、といったズレが生じている状態。

CakePHP3.4.6にアップデートしました!

f:id:itosho525:20170430222524j:plain

こんにちは。 GWはずっと欅坂46の『不協和音』を聴いていたサーバーサイドエンジニアの@itoshoです。 前回のエントリーからCakePHP3アップデートの連載?を担当しています。

そして、早速GW中に新しいバージョンである3.4.6がリリースされましたので、今回も簡単にではありますがアップデート内容をまとめさせていただきました。

CakePHP3.4.6の変更点まとめ

今回は以下の変更がありました。

  • CSRFとセキュリティトークン用のフィールドのautocomplete属性を明示的に無効にした
    • 新しいSafariのバックボタンの挙動で、blackholedエラーが発生する問題を解決しています。
  • SQLServerの接続ドライバーに多数のオプションが追加
    • 具体的にはコネクションプーリングやログインタイムアウト等のオプションが追加されました
  • APIドキュメントの改善
  • FixtureのDB接続のコネクションが常に別名を使うように修正
    • これによりテスト時に利用するDBが定義されていない時に、誤って生(≒本番)データに接続する危険が回避されます。
  • 翻訳パッケージ(Aura.Intl)が、Cake3.3で生成されたキャッシュファイルからinitializeする時に発生していた不具合を修正。
  • and*()メソッド及びor*()メソッドに追加される条件句(conditions)をいずれも後ろに追加するように修正
    • 以前は and*()メソッドは条件句を後ろに追加、or*()メソッドは条件句を前に追加(prepend)していました。
    • 生成されるSQL文としては順番が逆でも影響はありませんが、混乱するので統一したようです。

詳細は公式のリリースノートをご覧ください。

また、リリースノートには記載されていませんが、GitHubのREADMEにCakeのロゴが追加されたようです!

アップデート時にやったこと

3.4.5へのアップデート同様、今回も軽微な変更のみだったので、composer updateコマンドを実行後、CIが通っていればOKとして、リリースを行いました。

おわりに

日々開発しているシステムに不協和音が起きないようにフレームワークのアップデートは早め早めに実施していきましょう。(自戒も込めて)

CakePHP3.4.5にアップデートしました!

f:id:itosho525:20170430222524j:plain

こんにちは! 3月からコネヒトで頑張っているアイドル大好きエンジニアの@itoshoと申します。 最近はBiSHさんの『プロミスザスター』をヘビロテしています。

いきなりですが、皆さんは普段Webアプリケーションフレームワークのバージョンアップをどういうタイミングで実施していますか? 影響が少なそうなマイナーバージョンアップであっても、ついつい先延ばしにしてはいないでしょうか。

しかし、そうやって先延ばしにしていると、いざバージョンアップしようと思った時に影響範囲のチェックや動作確認のコストが大きくなりがちで「まだ暫くこのままでいいか…」と二の足を踏んで、気付けばいつの間にか最新バージョンに追従出来ないレガシーなシステムを生み出してしまうことになりかねません。(僕も過去にそのような苦い経験がございます…)

コネヒトではWeb APIの開発をCakePHP3を利用して行っているのですが、そのようなシステムを生み出さないように、新しいバージョンが出た際は積極的にバージョンアップするように努めていまして、今日はつい先日実施した3.4.4から3.4.5へのバージョンアップの内容について書きたいと思います。

ちなみに、CakePHPのHTTPリクエスト / レスポンスのインターフェイスが3.4系からPSR-7準拠に生まれ変わっており(素晴らしい!)、今後deprecatedなメソッドが増えることが予想されるので、まだ3.3以下のバージョンを利用されている方はお早めのバージョンアップをオススメします!

CakePHP3.4.5の変更点まとめ

詳細な情報は公式のリリース情報をご覧いただければと思いますが、今回は以下の変更がありました。

  • PaginationHelperで複数の値が設定されたソートリンクがデフォルト以外のモデルだと正しく生成されない不具合の修正
  • CSRFエラーとMissing Controllerが発生した際のエラーメッセージの改善
  • Diactorosというライブラリ起因で発生するHttp\Client\Requestクラス内でのエラー修正

また、公式ページに記載されているのは上記の3つなのですが、changelogをみてみると.travis.ymlからHHVMの記述が消えているので、興味ある方は実際のコードを読んでみると思わぬ発見があるかもしれません。

アップデート時にやったこと

3.4.4からのアップデートで、今回は軽微な不具合の修正のみだったので、composer updateコマンドを実行後、CIが通っていればOKとして、リリースを行いました。(アップデート後も特に不具合は起こっていません)

こういう時、きちんとテストコードを書いておくと安心ですね!

おわりに

今回はマイクロバージョンアップなので、問題なく最新バージョンにアップデートすることが出来ましたが、これからCakePHPをバージョンアップした際はこのブログでご報告させていただいて、微力ながらCakePHP界隈を盛り上げていくことをプロミスしますので、今後ともよろしくお願いいたします!

追伸

この記事をしたためている間に3.4.6がリリースされたので、それについても近日中にまとめたいと思います!

チームでのAPI開発の強い味方!!REST APIクライアント「Paw」と「Insomnia」を比較してみた

f:id:supermanner:20170502152129j:plain

こんにちは!今年もコナン映画にいってきました、コナンでは服部派のエンジニア結城(@super_manner)です(*´ڡ`●) さて、今回はAPIをチームで開発するうえでつよーい味方になるツールを2つ使い比べた結果をご紹介しようと思います!!

そもそもPawとInsomniaとは?

双方ともREST APIクライアントです。

Paw paw.cloud Insomnia insomnia.rest

APIを作成していると、POSTする必要があったり、User-AgentやRequestHeaderによる制約を受けたりで プラグイン追加が加速したりしますよね。
うっかりそのまま他のサイトを閲覧して全部がxmlで表示されたりすることもしばしば。
そんな煩わしさも、これらのクライアントを使うことで開放されるのです!!
APIをメインに開発されている方にはもはや必需品になっているかもしれませんね。 百聞は一見にしかずなので、試しに国土交通省のAPIを叩いた画面を見てみましょう。 *1

PawでGETした様子 f:id:supermanner:20170427205919p:plain InsomniaでGETした様子 f:id:supermanner:20170427210037p:plain

このように、各種設定をしてあげることで簡単に何が返ってくるかを確認することができます。

共有ツールとしてのおすすめポイント

わかりやすいUIなので、初めて使う方でも迷うことなく使っていただけるのがいいところです。
以下、参考画像はInsomniaのものですが、Pawも同じ機能がついています。(詳しい比較は後述します)
このように、階層構造でendpointを管理できたり、パラメータやヘッダ情報もまるっと共有できます! f:id:supermanner:20170501183349p:plain f:id:supermanner:20170501192159p:plain こちらは、環境変数を管理できる機能です。共通して使う変数と、そうでないものを切り分けできて便利です。 f:id:supermanner:20170501205120g:plain

また、snippetを自動生成してくれるのでPull Request等に貼り付けると、レビュワーに優しいですね\(^^)/ f:id:supermanner:20170501195328g:plain

2つのツールの機能比較

さて、ツールの紹介が終わったところで本題です。
コネヒトのAPI開発陣はトライアル期間を経て2つのツールの選択をせまられました… ツールの選択はいついかなるときも難しいものですよね。
ということで、2つのツールを比較し、できること、できないことを表にしてみましたので御覧ください。

Paw Insomnia 備考
RequestHeaderの設定
パラメータの設定
cookieの設定
環境ごとの変数の設定 例えばですが, {local/dev/stg/prod} 等で別途環境変数をマネージする機能があります
snippet発行 ただし双方で発行できるsnippetの種類に違いがあります
設定のimport/export
複数のapiを同時に叩く
teamアカウントを発行できる teamを作成することで、登録したapiの設定を共有できます
ブランチ機能がある ブランチ機能については後述します
料金 個人プラン:$49.99
チームプラン:月額$10
制限付き$0
有料プラン:月額$5
チームプラン月額:$8

Pawのほうが少し料金が高めですが、その分機能が多いですね。
InsomniaでできることはPawですべて網羅していると言っても過言ではないでしょう。(もちろんsnippetの発行形式など細かな違いはあります)
また、個人でcloudにプロジェクトをもつことのできる個人プランはいいお値段です!
そんな多機能なPawですが、中でも特筆すべき機能としてブランチ機能があります。

Pawのブランチ機能について

公式のドキュメントが非常に丁寧に書いてあるので、基本的な使い方はこちらを参照していただけると良いかと思います。 さぁ、セクションタイトルを見てみましょう!

Manage your workflow with branches

何処かで見たような機能ですね。そうです!我々も馴染みが深いgitと同じです。 開発中のapiなどはいきなりみんなに共有しても「これ開発中です!」と宣言して回る訳にはいきません。
そのような場合は自分用にブランチを切って、そこで登録していけばmasterはスッキリと余分なものが登録されないまま保たれます! チームにとっても、自分にとっても常に動くものが簡単に手に入りますb

Insomniaのデータ共有はどうなっているの?

先程の表で述べた通りInsomniaにもteam機能があり、workspaceとよばれる箱でデータを共有することができます。
が、現時点では手元のデータとremoteのworkspaceの同期だけで、git pullのような機能は実装されていません
つまり、手元で変更してしまうとその時点で残念ながらremoteのデータとはズレが生じてしまい、復旧の術がないということです。
dropboxをイメージしていただけるとわかりやすいかと思います。 cloud上のworkspaceと完全一致していない場合は下図のようにどれだけズレているのかが%で表示されています。
f:id:supermanner:20170429174502p:plain

英語ドキュメントの読み逃しがこわかったため、運営チームに問い合わせをさせていただいたところ、下記の返答を頂いたので将来的には実装されるかもしれませんね!!期待して待ちましょう。

Hi Mana,

Thanks for reaching out :)

There is no official way to do a pull master currently. For now, I recommend duplicating the request (or folder) that you want to edit so that you do not modify the existing data.

I will be sure to consider this use case as I improve the team features in the future.

Let me know if that works for you.

まとめ

2つのツールの機能比較をして、現在私のチームではInsomniaにチーム課金して使用しています。
なぜなら、いまのところREST Clientの使用理由が

  • 実装したAPIの各環境での実行確認をするため
  • テストで使用したrequest情報を完全再現してレビュー時にレビュワーにわかりやすくするため

の2つであるからです。
ですので、機能としてはシンプルで、料金もお財布に優しいInsomniaを採用し日々の開発に役立てています。 しかし今回記事を書くにあたって改めて調べてみるとPawの機能はまだ全然つかいこなせていなかったなぁと思ったので、 今後も使って有用だった機能があれば引き続き紹介していきたいと思います!*2

双方ともまだまだ開発は進んでいるようなので、みなさんもよければぜひ活用して素敵なAPIライフを送ってください!

*1:http://www.land.mlit.go.jp/webland/api.html

*2:pawのdocの厚さがものすごい

デザイナーの生産性を高める3つの改善策

f:id:connehito:20170331142331p:plain

お疲れ様です!デザイナーのきよえし(@kiyoe_furuichi)です。 今回は「生産性」というテーマと戦って得た学びについて書いてみたいと思います。 少し長いので、お茶でも飲みながらゆっくり読んでくださいね。

生産性とは

インプット(成果を生み出すためのヒト・時間・情報など)に対するアウトプットの比率のことを「生産性」と言います。 生産性は、少ないインプットで大きなアウトプットを得られると生産性が高いと評価され、大きなインプットの割にアウトプットが小さいと生産性は低いとされます。

デザイナーのお仕事で例えると、バナーを1日で作成してリリースするのと、半日で作成してリリースをするのとを比較して、成果物は同じものだとすると後者の方が「生産性が高い」ということになります。

きっかけ

「忙しい」を理由に思考時間を減らすのをやめたいと思ったことがきっかけでした。 サービスの成長と共にチャレンジできることが増え、好きな領域で活躍できることが嬉しい一方、目の前のissueに追われ本質からモノゴトを考える余裕がなくなっていました。 そんな状況だと質の高いアウトプットは出せない・精神衛生上良くない = 生産性が低下するという問題意識から、自分の仕事のやり方を見直すことにしました。

実践

生産性を高めるために実践したことは以下の3つです。

  1. RescueTimeで消費時間を可視化する
  2. issueを細かく分解する
  3. 情報を断捨離する

補足すると、今回は特に問題意識の高い「時間の使い方」にフォーカスして実践しました。時間の使い方が上手になると本質的な作業への消費できる時間が増えるため、デザインの質が上がり、生産性が高まると考えたためです。

1. RescueTimeで消費時間を可視化する

RescueTime(以下レスキュータイム)というツールを使って、1日の作業内容のうち、本質的な作業にどれだけ時間を消費できたかどうかを計測します。

例えばこのログをご覧ください。私の記念すべき初レスキュータイムの結果です。

f:id:connehito:20170330201240p:plain (本質的な作業 = Software Development + Design & Composition)

グラフを見ると、1日の作業時間の約30%がCommunication (to Slack)に消費されていることがわかります。本質的な作業よりもコミュニケーションの時間が掛かっているのは健全ではありません。 レスキュータイムのログを毎日退社前に見ながら、1日を振り返って改善ポイントを洗い出します。 ちなみにこの日は以下のような反省をしました。

Slackの閲覧時間が多くなってしまう原因として、モニター上に表示しっぱなしで新着の投稿があると気になって開いてしまうことがあげられる。必要なとき以外は目に止まらないようにウィンドウを非表示にしたり不要なチャンネルをミュートするなどで工夫をしよう。

2. issueを細かく分解する

(このやり方はgithub/ZenHubを利用した進捗管理を行なっている方に限定されます)

issueの粒度を細かくすることでアウトプットのゴールを明確にします。 そうすることで1作業に対しどのくらい時間を消費したかどうかが見やすく振り返りもしやすくなります。

例えば「新しい機能のUI設計」というissueがあるとします。細分化するとそのissueをepic(親)としてUI設計に必要な工程ごとにこのように分けることができます。

  • 【epic】 新しい機能のUI設計
    1. 【issue】 アイデア出し
      • ゴール:頭の中でイメージを固める
    2. 【issue】 ワイヤー作成
      • ゴール:ディレクターにOKをもらう
    3. 【issue】 Sketchデータ作成__iOS
      • ゴール:prott確認ができる状態に落とす
    4. 【issue】 Sketchデータ作成__android
      • ゴール:prott確認ができる状態に落とす
    5. 【issue】 確認・修正
      • ゴール:ディレクター・エンジニアと確認を行い、OKをもらう
    6. 【issue】 Zeplinデータ納品
      • ゴール:ZeplinデータをiOS/androidエンジニア両方に納品する

細分化すると一覧として見たときにすごい量になり管理が難しくなりますが、ZenHub(ゼンハブ)というプロジェクト管理ツールでissue管理を行い、次やるべきissueや進捗が明確になるようにしています。

f:id:connehito:20170330201327p:plain

in Progress が現在着手しているissueで、in Reviewがレビュー中、そしてDesign には1スプリント内に着手するissueが順番に並んでいます。

3. 情報を断捨離する

1に記載したレスキュータイムを始めてから、コミュニケーションで時間を消費しすぎているという課題を発見したため、見るもの・見ないものを分別して情報の断捨離を行いました。 主に以下の3つを意識して時間の節約を行なっています。

① タイムラインは閲覧を控える

Slackやカレンダー、SNSなどタイムラインを追うツールはマインドシェアを取られがちなので必要以上には見ないようにしています。
特にSlackの分報の使い方には注意しています。気軽に気づきやつらみを共有することを目的とするチャンネルですが、ついおしゃべりをしてしまうので時間を区切って見るなど常駐しないように気をつけています。

② 大事なことを見逃さないように工夫する

タイムラインの閲覧を控えると、タイムラインが流れてしまい大事な要件を見逃してしまうことがあります。うっかりしないよう、以下のSlackの設定で予防できるようにしました。

  • Slackの /remind機能を利用し、タイムラインを見る頻度を減らす
  • 必ず見るChannelは通知が来るように設定し、見逃しを予防する
  • 定期的に見ないChannelはミュートし、見るべきものだけにフォーカスできるようにする

③ 1次情報をなるべくチェックする

タイムラインの閲覧を制限すると得られる情報に偏りがでてしまうため、議事録やメモなど、まとめられた資料を読んでキャッチアップしています。 コネヒトではDocBase(ドックベース)というドキュメント共有ツールを利用しているので、そちらに投稿されたものは毎日数分時間を取って読んでいます。

f:id:connehito:20170331142058p:plain

成果

上記3つを3ヶ月間実践した結果、3つの改善をすることができました。(333!)

1. 本質的な作業への消費時間が増えた

RescueTimeを見ると時間の使い方が大分良くなったことがわかります。
1日の作業時間のうち、本質的な作業に消費する時間が40%から64%と約1.5倍の改善を達成することができました。

f:id:connehito:20170330201425p:plain (本質的な作業 = Software Development + Design & Composition)

2. デザインの質が上がった

1issueに掛ける時間を増やしたことで、制作後の手戻り回数を減らすことができました。さらに 1スプリント内に消化できるストーリーポイントの合計が22ptから48ptと2倍近く増え、着手できるissueをかなり増やすことができました。(まぐれかもしれないので、引き続き邁進します)

f:id:connehito:20170330201435p:plain

3. 気持ちに適度な余裕ができた

時間に余白をつくることができたため、納品が近い成果物があった場合も気合いで解決することがなくなりました。切羽詰まるような不安要素がなくなり、健全な気持ちでモノゴトに立ち向かえるようになりました。

終わりに

生産性というテーマと向き合う中で、デザイナーとして一歩成長することができました。サービスのことを俯瞰して考える時間が増え、自分自身が納得感を持てるアウトプットを出せるようになったからです。
とはいえ、今回ご紹介した改善策は、"マイナスをゼロに戻すためのもの"だと考えています。
「生産性を高める」ということにおいて、良いアウトプットを出すためにはやっぱりスキル面を磨かないといけません。そのために、今後はゼロからプラスにするための改善に取り組んでいこうと考えています。最後まで読んでいただき、ありがとうございました!

参考