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

コネヒト開発者ブログ

コネヒト開発者ブログ

デザイナーの生産性を高める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. 気持ちに適度な余裕ができた

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

終わりに

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

参考

Kotlin1.1の新機能について

f:id:tommy_kw:20161106193050p:plain

こんにちは!@tommykwです。先日のDroidKaigiとても楽しかったですね。2日間参加させていただき、どのセッションも素敵なセッションで学びのある時間を過ごせました。スタッフ、スピーカー、参加者の皆さん、ありがとうございました!

さて、Kotlin1.1が3/1にリリースされました。早いものでもう3週間ほど経ちますが、すでに利用されている方も多くいらっしゃるのではないでしょうか。Kotlin1.1では多くの機能がリリースされましたが、今回はKotlin1.1で導入された便利な新機能をいくつか情報共有したいと思います。

今回紹介する新機能

  • Alt+Enter
  • _キーワード
  • 型エイリアス
  • ::キーワード
  • データクラス継承

Alt+Enter

Alt+EnterとはIntentionと呼ばれるもので、Android Studio上でAlt+Enterすることによって簡単にクイックフィックスできる機能です。 高速コーディングを支える技術で、Kotlin1.1で新しく追加されたクイックフィックスについて紹介したいと思います。

  • Add Android View constructors using @JvmOverloads

Android開発でカスタムViewを作る場合はコンストラクタを複数定義する必要があり、とても冗長になります。 それをKotlinの@JvmOverloadsを使うことによって簡潔に記述できます。 f:id:tommy_kw:20170317080730g:plain

簡単ですね。しかし、以下のように既にコンストラクタを定義した場合はクイックフィックスできません。 この状態からコード最適化できるとリファクタリングが容易です。

class CustomView: View {
    constructor(context: Context) : this(context, null) {
    }
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
    }
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
    }
}
  • Convert to range check

範囲指定しているif文をRange型に変換します。 f:id:tommy_kw:20170317082139g:plain

  • Merge ‘if’s

ネストしたif文をマージします。 f:id:tommy_kw:20170317082603g:plain

  • Use destructuring declaration

ラムダで分解宣言を使うことによって、オブジェクトからデータを取り出して別の変数に代入します。 f:id:tommy_kw:20170317224853g:plain

よく見ると、fun main(args: Array<String>) {} と記述するとKotlinアイコンが表示されますね。 エラー、警告表示があった時に取り敢えずこのショートカットを使えば役に立ちますし、特にカスタムViewのクイックフィックスは Kotlinっぽく記述できてコーディングが捗りそうです。

_キーワード

Swiftでもお馴染み_キーワードで、パラメータを省略するためのキーワードです。 ママリQにて、Kotlin1.1にアップグレードした際にLintで未使用な変数である旨の警告が大量に表示されました。そんな時に利用したのが_キーワードになります。使用用途としては以下の通り、ラムダの引数、無名関数の引数、分解引数で利用できます。

  • ラムダの引数
// v, hasFocusパラメータを定義する
view.setOnFocusChangeListener { v, hasFocus ->
}

// v, hasFocusパラメータを省略する
view.setOnFocusChangeListener { _, _ ->
}
  • 無名関数の引数
// xパラメータを定義する
val function = fun(x: Int) {}

// xパラメータを省略する
val function = fun(_: Int) {}
  • 分解引数 その1
// a, b, cパラメータを定義する
val (a, b, c) = listOf(1,2,3)

// bパラメータを省略する
val (a, _, c) = listOf(1,2,3)
  • 分解引数 その2
// a, b, cパラメータを定義する
listOf(Triple(1, 2, 3)).forEach { (a, b, c) -> }

// a, cパラメータを省略する
listOf(Triple(1, 2, 3)).forEach { (_, b, _) -> }
  • onClickイベントのunusedなView引数

AndroidでよくあるパターンのonClickイベントのView引数がunusedになる問題ですが、

fun onPhotoClick(@Suppress("UNUSED_PARAMETER") view: View) {
    // do something
}

残念ながら以下の様にメソッドの引数には適用できません。unusedを回避するには@Suppress(“UNUSED_PARAMETER”) アノテーションをつけるのが良さそうです。

fun onPhotoClick(_: View) {
    // do something
}
  • _キーワードに型を明示的に定義

Function型の引数が複数ある場合に{}{ _ -> }で記述するか悩むケースがあります。 以下はRxJavaを用いたサンプルになります。

// RxJava1の非同期Extension
fun <T> Observable<T>.async(onNext: (T) -> Unit, onError: (Throwable) -> Unit) {
    this.subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(onNext, onError)
}

// APIクライアントからメンバーカウントを取得する
apiClient.memberCount()
    .async(
        { result ->
            if (result.count > 0) {
                // do something
            }
        }, 
        { e ->  } // 未使用のeが未使用となる
    )

上記の{ e -> }{}に変えても良いですし、{ _: Thowable -> }と型指定した宣言をしても良いのではないでしょうか。 多少冗長になりますが、個人的には可読性が上がる場合もあるかなと思います。

apiClient.memberCount()
    .async(
        { result ->
            if (result.count > 0) {
                // do something
            }
        }, 
        { _: Thowable ->  }
    )

型エイリアス

型エイリアスは既存の型を別の型として提供でき、関数、コレクション、コンパニオンオブジェクト、ネストしたクラスなどに適用できます。 トップレベル宣言、メンバー宣言、ローカル宣言をすることができますが、Kotlin1.1ではトップレベル宣言のみサポートされています。

以下はKotlinのstdlibのコード内で型エイリアスを利用しているケースですが、本来importする必要があるライブラリを型エイリアスを使うことによって、利用する側はimport不要で利用出来るのが良いです。

TypeAliases.kt

@file:kotlin.jvm.JvmVersion

package kotlin.collections

@SinceKotlin("1.1") public typealias RandomAccess = java.util.RandomAccess


@SinceKotlin("1.1") public typealias ArrayList<E> = java.util.ArrayList<E>
@SinceKotlin("1.1") public typealias LinkedHashMap<K, V> = java.util.LinkedHashMap<K, V>
@SinceKotlin("1.1") public typealias HashMap<K, V> = java.util.HashMap<K, V>
@SinceKotlin("1.1") public typealias LinkedHashSet<E> = java.util.LinkedHashSet<E>
@SinceKotlin("1.1") public typealias HashSet<E> = java.util.HashSet<E>


// also @SinceKotlin("1.1")
internal typealias SortedSet<E> = java.util.SortedSet<E>
internal typealias TreeSet<E> = java.util.TreeSet<E>

さらに、以下のAnnotations.ktを見ていただくといくつかのアノテーションをサポートしていることがわかります。 型エイリアスは@Deprecated, @SinceKotlin, @Suppressアノテーションを許可されていて、別名の型として利用する機会はあると思いますが、アノテーション付きで定義できるところが良いなという印象です。

Annotations.kt


@Target(CLASS, FUNCTION, PROPERTY, ANNOTATION_CLASS, CONSTRUCTOR, PROPERTY_SETTER, PROPERTY_GETTER, TYPEALIAS)
@MustBeDocumented
public annotation class Deprecated(
        val message: String,
        val replaceWith: ReplaceWith = ReplaceWith(""),
        val level: DeprecationLevel = DeprecationLevel.WARNING
)

@Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER,
        CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPE, EXPRESSION, FILE, TYPEALIAS)
@Retention(SOURCE)
public annotation class Suppress(vararg val names: String)

@Target(CLASS, PROPERTY, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPEALIAS)
@Retention(AnnotationRetention.BINARY)
@MustBeDocumented
public annotation class SinceKotlin(val version: String)

このような未定義を表したカスタムViewクラスも定義できますし、@Suppressアノテーションもうまく利用できるかもしれません。

@Deprecated("unused view")
typealias DeprecatedView = View

::キーワード

::キーワードが追加されました。これはJavaの<expression>::classメソッド参照と<expression>::<member name>メンバー参照をサポートしています。 毎回ラムダで少し冗長に記述するのではなく、::キーワードを使ってより簡潔に記述できます。

// ラムダ
listOf("a","b","c").map { it.toUpperCase() }

// メソッド参照
listOf("a","b","c").map(String::toUpperCase)
data class Member(val id: Int)
// ラムダ
intArrayOf(1,2,3).map { Member(it) }

// メソッド参照
intArrayOf(1,2,3).map(::Member)

また、KClassを取得するのに、.javaClass.kotlinがありましたが、::classを使ったほうがよさそうです。 以下のコードからもわかるように、.javaClass.kotlin::classでは動作が異なるため、.javaClassはDeprecatedになっていく予定のようです。

class Foo {
   fun bar() {
      val a: KClass = this.javaClass.kotlin
      val b: KClass = this::class
 
      a.memberProperties.forEach { property: KProperty1<Foo, *> ->
          property.get(this)
      }
 
      b.memberProperties.forEach { property: KProperty1<out Foo, *> ->
          property.get(this) //Error: Kotlin: Out-projected type 'KProperty1<out Foo,*>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'
      }
   }
}

データクラス継承

データを保持するクラスとして便利なdata classがありますが、これは継承することができませんでした。以下の通り、Kotlin1.1からsealed classやopen classを継承できるようになり、柔軟なデータクラス設計ができるようになりました。

open class Base(
    open val id: Int, 
    open val name: String
)

data class Member(
    override val id: Int,
    override val name: String,
    val age: Int
) : Base(id, name)

val member = Member(1, "foo", 20)

今までは生成されるコードの一貫性を保つために、クラスを継承できない仕様になっていました。インターフェースは実装することができましたが、 sealed classやopen classを継承できるのはとても便利です。

Kotlin 1.0.7、1.1.1リリース

早いですね!1.0.7は現時点でバージョン1.1にアップグレードできないユーザが利用できるように、Gradleおよびアノテーション処理に関連する修正をバックポートできるバージョンです。1.1.1は1.1.0のバグ修正がメインで一部のIDE、Compiler、Librariesの修正を行っています。特に問題ないのであれば、1.1.1の利用をオススメします。

まとめ

Kotlin1.1の新機能について簡単に説明しましたが、いかがでしょうか。本来であれば、Kotlin1.1のメイン機能であるCorutinesについて情報共有できれば良かったのですが、正直まだ使いどころがわかっていません。こちらは引き続き理解を深めていきます。また今回紹介していない新しいスコープ関数provideDelegateオペレータなどすぐに利用出来る便利な機能がたくさんリリースされました。これらをうまく利用することで、Kotlinの言語機能を最大限に活かせそうです。それでは楽しいKotlinライフをお過ごしください!

Dangerで始めるPull Requestチェック自動化

f:id:Utmrer:20170228201418p:plain

こんにちはー!こねひとちほーのえんじにあのフレンズ@Utmrerだよー!

今回はPull Requestを自動でチェックしてくれるDangerについて紹介します。

Pull Requestでのコミュニケーション

Pull Requestのレビューは不具合の指摘やコーディングスタイルの統一、より良いコードのための提案などのために行われます。 ですが、次のようなコミュニケーションをしたことはありませんか…?

  • タイトルにIssue Idを含めてもらえますか?
  • WIPみたいなんですがレビューして大丈夫ですか?
  • Base branchが間違ってます、変更してください。
  • 変更履歴のdocsを更新してください。

このような「実装とは関係のない指摘」はできるだけ減らし、自動化したいものです。それを実現するのがDangerです。

Dangerとは

DangerのGitHubには次のように書かれています。

Formalize your Pull Request etiquette.

Stop saying “you forgot to …” in code review

つまり「Pull Requestの作法を形式化して指摘を自動化」するツールです。

DangerがチェックするのはPull Requestの体裁なのでそのPull RequestがSwiftのプロジェクトであろうがRubyであろうが関係なく、すべてのプロジェクトに導入可能です。 実際にRxSwiftというSwiftのプロジェクトやcapistrano、sentryなど様々なプロジェクトで導入されています。

Dangerの導入

Travis上でDangerを実行し、GitHubのPull Requestにコメントするところまでを説明します。

Gemfileの設定

GemfileにDangerを追加します。これだけでTravis上でDangerを実行できます。

source 'https://rubygems.org'

gem 'danger'

Dangerfileの追加

プロジェクトのルートディレクトリにDangerfileというファイルを追加します。

このファイルにDangerにどのような項目をチェックしてもらうかを記述していきます。

warn('あぶないよー!')

warn(message)と書くと「これは注意が必要だよ」とGitHubにコメントします。

通常は特定の条件によってコメントするのでifなどで囲みますが今回はこのままにしておきます。

.travis.ymlの設定

.travis.ymlにDangerを実行するように設定します。

cache:
  - bundler
before_script:
  - bundle exec danger

Cache機能を使えば毎回bundle installを実行する必要が無いので時間節約のためにおすすめです。

Travis環境変数の設定

TravisからGitHubへコメントするため、TravisにGitHubのアクセストークンを設定する必要があります。 アクセストークンはこちらのページから作成できます。

Dangerでは公開プロジェクトではpublic_repo、非公開プロジェクトではrepoの権限を持ったアクセストークンが推奨されています。

また、この時にアクセストークンを発行するGitHubアカウントは普段使っている個人アカウントではなくBot用のMachineアカウントの方が良いです。GitHubは1人1アカウントのMachineアカウントの作成を許可しています

発行したアクセストークンはTravisの各Repositoryのsettingsページで設定します。 f:id:Utmrer:20170228161943p:plain Environment VariablesDANGER_GITHUB_API_TOKENというNameで先程のアクセストークンを追加します。

Pull Requestの作成

以上でDangerの最低限の設定は終了です。Pull Requestを作成するとDangerからコメントが来ます。 f:id:Utmrer:20170228200733p:plain

ここまでの導入方法はDangerの公式HPにも載っています。 GitLabを利用している方やCircle CIを利用している方はこちらからご自分の環境にあった方法で導入してください。

構文

DSL

Dangerにはコメントを書き込むDSLがいくつかあり、最もよく使うであろう3つのDSLを紹介します。

📖 message

messageは単純にコメントを書き込むDSLです。定型文を返す時などに使えそうですね。

message('Pull Requestありがとうございます。レビューまで少々お待ち下さい。')

⚠ warn

warnは出来れば修正して欲しい、もしかしたら違反しているかもという場合に使います。Pull Requestのタイトルやディスクリプションに関するものはwarnがいいでしょう。

warn('descriptionを300字以上書いて下さい')

🚫 fail

failは許容できない内容の場合に使いましょう。このDSLを利用した時、Commit stateはfailureになります。

fail('LICENSEファイルは変更しないで下さい。')

変数

環境によってDangerfile上で扱える変数がいくつかあります。これらを組み合わせることでルールを作っていきます。今回はGitHub環境で使えるgitgithubについて紹介します。

git

gitという変数にはPull Requestの対象となっているCommitの情報などが含まれています。例えば「編集したファイルの一覧」「削除した行数」などです。

if git.deleted_files.include? "LICENSE"
  fail('LICENSEファイルは変更しないで下さい。')
end

github

githubという変数からPull Requestの情報が取得できます。github.pr_jsonからPull Request全体の情報を取得でき、GitHubのAPI Referenceなどを読むとgithub.pr_jsonにどのような値が入っているかわかるでしょう。

よく使うデータには専用の関数が用意されていてgithub.pr_titlegithub.pr_bodyからタイトルやディスクリプションがをシンプルに取得できます。

if !github.pr_json['mergeable']
  fail('マージできません。')
end
if !github.pr_title.include? "WIP"
  warn('このPull Requestは実装途中です。')
end

詳しくはReferenceをご覧ください。

Danger導入事例

Dangerの導入方法がわかったところで、OSSプロジェクトがDangerでどのようなことを行っているか見てみましょう。

capistrano

capistranoではDangerfileで次のようなことをチェックしているようです。

has_lib_changes = !git.modified_files.grep(/^lib/).empty?
has_test_changes = !git.modified_files.grep(/^(features|spec)/).empty?
has_changelog_changes = git.modified_files.include?("CHANGELOG.md")
if has_lib_changes && !has_test_changes
  warn("There are code changes, but no corresponding tests. "\
       "Please include tests if this PR introduces any modifications in "\
       "#{project_name}'s behavior.",
       :sticky => false)
end

「Libraryに変更があったならテストを書こう」ということをチェックしていますね。Reviewerに指摘される前にTestが書ければコミュニケーションが減って時間の節約になります。

if !has_changelog_changes && has_lib_changes
  markdown <<-MARKDOWN
Here's an example of a CHANGELOG.md entry (place it immediately under the `* Your contribution here!` line):
 ```markdown
* [##{pr_number}](#{pr_url}): #{github.pr_title} - [@#{github.pr_author}](https://github.com/#{github.pr_author}).
 ```
MARKDOWN
  warn("Please update CHANGELOG.md with a description of your changes. "\
       "If this PR is not a user-facing change (e.g. just refactoring), "\
       "you can disregard this.", :sticky => false)
end

またLibraryに変更があったならCHANGELOG.mdに変更点を書くように促しています。これは商用プロダクトでもHelpの更新や仕様書の更新などに使えそうなロジックです。

capistrano/Dangerfile

Sentry

SentryではPull Requestの体裁に関するものがいくつかあります。

# Make it more obvious that a PR is a work in progress and shouldn"t be merged yet
warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]" || github.pr_body.include?("#wip")

タイトルとディスクリプションをチェックしてPull RequestがWIPかどうかを判定しています。WIPなのにReviewをお願いすることを防げますし、Reviewerも「WIPなので見なくて大丈夫!」と判断できます。

@S_BIG_PR_LINES ||= 500
# Warn when there is a big PR
warn("Big PR -- consider splitting it up into multiple changesets") if git.lines_of_code > @S_BIG_PR_LINES

Pull Requestの実装行数が大きすぎる場合は分割するように促しています。実装内容が膨大なPull RequestはReviewが大変ですし、不具合が紛れ込む可能性も高いので分割してPull Requestを作るのは良いことですね。

sentry/Dangerfile

mamariQ

最後に、弊社のママリQ iOSアプリのDangerfileを公開します。

# --------------------
# test
# --------------------
is_source_changed = !git.modified_files.grep(/^mamariQ\/Classes/).empty?
is_test_changed = !git.modified_files.grep(/^mamariQTests\/Case/).empty?

if is_source_changed && !is_test_changed
  warn('コードの変更がありますが、テストの変更がありません。必要であればテストを追加・修正しましょう。')
end

# --------------------
# base branch
# --------------------
is_to_master = github.branch_for_base == 'master'
is_to_release = !!github.branch_for_base.match(/release-[0-9]+\.[0-9]+\.[0-9]/)
is_from_release = !!github.branch_for_head.match(/release-[0-9]+\.[0-9]+\.[0-9]/)

if is_to_master && !is_from_release
  warn('masterへmerge出来るのはrelease branchのみです。')
end

if is_to_release
  warn('release branchに対してPRを向けないで下さい。develop branchに向けてPRを作成し、develop branchをrelease branchにmergeしてください。')
end

# --------------------
# pr title
# --------------------
is_wip = github.pr_title.include? '[WIP]'

if is_wip
  warn('このPRは作業中です。')
end

is_to_develop = github.branch_for_base == 'develop'
is_start_with_issue_id = !!github.pr_title.match(/^#[0-9]+/)

if is_to_develop && !is_start_with_issue_id && !is_wip
  warn('PRのタイトルは<b>「#XXX Foo bar...」</b>とIssue idから始めてください。')
end

# --------------------
# diff size
# --------------------
is_big_pr = git.lines_of_code > 500

if is_big_pr
  warn('PRの変更量が多すぎます。可能であればPRを分割しましょう。分割が難しければ次から気をつけるようにしましょう。')
end

弊社のiOS開発ではgit-flowを採用していて、Pull RequestにおけるBase branchの選択がちょっと複雑です。そのため、DangerでBase branchのチェックを自動化しています。このDangerfileを書いたのは私なのに自分で引っかかることがあってDangerに感謝感激です。

人は人にしか出来ないことを

DangerにはPlugin機能があり、機能を拡張できるので可能性は∞です。Android LintSwiftLintのPluginもあります。(私の環境ではSwiftLint Plugin動かなかったので動作は保証できないですが…)

そういえば、Dangerを作ったOrtaさんKrauseFxさんはtry! Swiftで講演されるようですよ。try! Swiftに行かれる方はDangerの話もしてみてはどうでしょう?私もいきます☺

機械に出来ることは機械に任せて、人は人にしか出来ないことに集中していきましょう。

Slackで簡単チェック!textlint で始める文字校正Bot

f:id:fortkle:20170216212251p:plain

こんにちは! 新オフィスに移転してから毎日2缶ドクターペッパーを買うのが習慣化してきた @fortkle です。

今回はSlackで簡単に文字校正ができるBotを作ってみたのでご紹介したいと思います。

手軽に校正したい

メールやチャットだけでなく、こういったブログやissueに書く仕様など「文章を書く」シーンはたくさんあると思います。

そんなとき自分が伝えたいことを相手にちゃんと伝えることができれば良いのですが、良い文章を書くのはなかなか難しく、今も試行錯誤しています。

そこで、相手に伝えたいことがちゃんと伝わる良い文章を書くためにSlack上で簡単に試せる文字校正Botを作ってみました。

成果物

実際に見たほうが早いと思うので画像を交えてご紹介します。 ちなみに ソースコードはGithubにあげている ので参考にしてみてください。

例として以下の文章をチェックしてみたいと思います。

この文章はご存知の通り、ダミーテキストです ヽ(^o^)丿
そして、様々な、エラーチェックに、引っかかる文章になっています。そして、意味はありません。
この文章が書くのが自動ではなく手動なのが地味に大変だったところです。
いや、大変だったとはいえないこともないです。このBOTはナウでヤングなやり方で
文章をチェックすることができます。チェック結果はslackで即座に見れます。
焦ってしまうとと誤字をすることがありますよね。そんなときに便利です。

チェックするにはSlackで文字校正Botに「check」から始まるDMを送るだけです。

check
ここにチェック
したい文章を
書きます。

実際に校正した結果がこちらです。

f:id:fortkle:20170216183734g:plain

1行目:ご存知 => 用字(ご存じ)
1行目:(^o^) => 顔文字が使われています。
2行目:様々 => 用字(さまざま)
2行目:エラーチェック => 半角カタカナが使われています。
2行目:同じ接続詞が連続して使われています。
3行目:一文に二回以上利用されている助詞 "が" がみつかりました。
4行目:こともない => 二重否定()
4行目:ナウ => 死語が使われています。
4行目:ヤング => 死語が使われています。
4行目:一文に二回以上利用されている助詞 "で" がみつかりました。
5行目:することができます => 冗長表現(できます)
5行目:見れ => ら抜き(見られ)
5行目:slack => 全角英数字が使われています。
6行目:"と" が連続して2回使われています。

どうでしょうか?意外と使えそうな気がしませんか! プロが使うような有料の校正ツールに比べると指摘内容は少ないですが、このように簡単に文字校正を試すことができます。

文字校正Botのメリット

誰でも簡単に使える!

まだ個人でしか使っていませんがもし会社で使うとなった場合でも、有償の文字校正ツールと違いSlackさえあれば誰でも利用できる手軽さがあります。 また、校正したいテキストをBotにDMで投げる形なのでチャンネルを汚すことなく利用できます。

自分が用意した辞書でカスタマイズできる!

実際の校正結果の画像をよく見ていただくと分かると思いますが、「顔文字」や「死語」などの指摘があるかと思います。 これらはどちらも自分で用意したオリジナルのルールです(死語はジョークルールですよ!)。 後述する prh というツールを使うと自分が用意した辞書を使って文章を校正することが出来ます。

校正内容のメンテナンスに夢が広がる!

今回は未実装ですが、実装さえすれば文字校正をするだけでなく校正内容も管理できると思います。

たとえば ng-word add [追加したい文言]ng-word remove [削除したい文言] などCRUD操作をできるようにしておけば Slack上から簡単に、しかも非エンジニアだけで校正内容をメンテナンスすることができそうですね!

仕組みの解説

今回の文字校正Botは Botkit をベースに textlintというツールを使ってSlack上での校正を実現しています。 Botkitのセットアップが終わりBotが動いている状態からスタートし、実際に文字校正ができるようになるところまでの実装手順をご紹介します。

1. 使っているツール

textlint

textlintは、@azu さんが作っている自然言語をLintできるツールです。JavaScriptにおけるESLintのように、あらかじめ設定しておいたルールに基づいて、テキスト上の間違いや読みにくい点などを指摘してくれます。

プラガブルであることが特徴でデフォルトでは1つもルールがありません。そのため、一般公開されているルールや自分で作ったルールを組み合わせる必要があります。

一般公開されているルールは こちら(Collection of textlint rule) で確認できます。 今回は校正のルールとして下記6つを採用しました。

採用ルール

2. インストール

textlint本体とルールをnpm経由でインストールしましょう。ここではyarnを使ってインストールします。

$ yarn add textlint textlint-rule-ja-yahoo-kousei textlint-rule-prh textlint-rule-no-doubled-conjunctive-particle-ga textlint-rule-no-doubled-conjunction textlint-rule-no-doubled-joshi textlint-rule-ja-no-successive-word

3. prh で使う辞書の作成

辞書はyaml形式で下記のように書くことができます(基本的な書き方はこちら を参考にしてください)。

version: 1
rules:
  # 大文字小文字全角半角の統一
  - expected: Cookie
  # 以下と等価 正規表現には強制でgフラグが付く
  # - expected: Cookie
  #   pattern: "/[CcCc][OoOo][OoOo][KkKk][IiIi][EeEe]/g"

  # 表現の統一を図る
  - expected: デフォルト
    patterns:  ディフォルト

さて、この設定ファイルを見ると分かる通り本来prhは表記ゆれを検出するためのツールですが、「独自の辞書を作れること」「エラーメッセージを辞書毎に設定できること」の2点から今回は簡易的なNGワードチェックのために使ってみることにします。本来の用途とは異なりますが、 expected に「エラーメッセージ」を書き、 patternにエラーにしたい単語を列挙します。

version: 1 
rules: 
  # 本来、expectedには「期待される値」が書かれるべきだがtextlint-rule-prhがprhフィールドに対応していないので「エラーメッセージ」を書く 
  - expected: 死語が使われています。 
    patterns: 
      - アイアム・ソーリー、ひげそーりー
      - あたりまえだのクラッカー 
      - アベック 
      - いただきマンモス 
      - うれピー 
      - おいくら万円 
      - オッケー牧場
      - ナウ
      - ヤング
      # (略)

4. textlint の設定ファイルを作成 ( .textlintrc )

次にtextlint の設定ファイルをJSON形式で作成し、 .textlintrc という名前で保存します。 .textlintrc には読み込みたいルールと設定を記述します。

{ 
  "rules" : { 
    "no-doubled-conjunctive-particle-ga": true,
    "no-doubled-conjunction": true,
    "no-doubled-joshi": true,
    "ja-no-successive-word": true,
    "ja-yahoo-kousei": true,
    "prh": {
      "rulePaths": [
        "./dict/prh.yml"  ← ここでprhで使う辞書を読み込む
      ] 
    } 
  }
}

ja-yahoo-kouseiルールを利用するためには事前にYahoo アプリケーションIDを取得する必要があります。 詳しくはREADMEを見てみてください。

5. textlintをモジュールとして使う

公式のドキュメントを参考に実装します。 実装例としてサンプルコードを載せておきます。

import path from 'path'
import {TextLintEngine} from 'textlint'

export default function(controller) {

  const engine = new TextLintEngine({
    configFile: path.join(__dirname, '../.textlintrc'),
  })

  const formatResults = (results) => {
    let output = '```\n'
    const messages = results[0].messages
    for (let i = 0; i < messages.length; i++) {
      const msg = messages[i]
      const msgText = `${msg.line}行目:${msg.message}\n`
      output += msgText
    }
    output += '```'

    return output
  }

  controller.hears([/^check[\n\r]([\s\S]*)/], ['direct_message'], (bot, message) => {
    const msgBody = message.match[1]

    engine.executeOnText(msgBody).then(results => {
      if (! engine.isErrorResults(results)) {
        bot.reply(message, 'エラーは見つかりませんでした。')
        return
      }

      let output = ''
      output += 'エラーが見つかりました。\n\n'
      output += formatResults(results)

      bot.reply(message, output)
    })
  })
}

これで実装は完了です!簡単なのでぜひ試してみてください!

最後に

さて、今回は textlint を使った文字校正Botについてご紹介しました。

textlintはまだまだ発展途上にあるため実務でがっつり使うにはまだ少し時間がかかるかな、というのが実際に使ってみた所感です。 特に用字用語や送り仮名、誤字脱字の検出に関しては辞書ベースの検出になるためどうしても力不足であることは否めません。 Yahoo! 校正APIを使うことである程度カバーできますが、textlintのルールは誰でも簡単に作ることができるので今後そのあたりをカバーするルールが充実するといいなと思いました。

もし興味があればルール作りなどにも挑戦してみてください!よいBotライフを!

非ネットワークエンジニアが社内ネットワークを構築したときに解決した3つの課題

f:id:tatsushim:20170203145647j:plain

こんにちは!

CTOの島田(@tatsushim)です。弊社は2017年から新オフィスに移転しました!

新オフィス移転に際して、必要になってくるのが新しい社内ネットワークです。 しかし弊社にはネットワークを専門に扱うメンバーがいません。 一方で移転することを決めてから3ヶ月というタイトなスケジュールの中でオフィス移転を実現する必要があったため、 自分たちで構築することにしました。

移転前のオフィスにおける3つの課題

1. Wi-Fiがたまに切れることがある

1つのネットワーク機器にアクセスが偏ったり、周波数帯が近いWi-Fiが存在して混線していたのが原因と考えられます。

2. Wi-Fiが遅くなることがある

Kitting*1でイメージファイル等の重いファイルのダウンロードが行われると、同じWi-Fiに接続している他の端末のネット速度が遅くなっていました。

3. いちいち場所を移動する度にWi-Fiを切り替える必要があった

AirMacを利用していたのですが、ブリッジ接続が上手くいかず、会議室と執務スペースでそれぞれ別のSSID*2で運用されていたために、移動した際に接続の切り替えを忘れていてネットに接続できずイライラ・・・なんてこともありました。

3つの課題に対する解決策

1. ネットワーク機器の適切な配置と周波数帯の設定

f:id:tatsushim:20170203122130p:plain こちらの図は、弊社の実際のオフィスの見取り図の上に各ネットワーク機器とそのカバー範囲をビジュアライズしたものです。 六角形の中心がネットワーク機器で、その機器からある程度均等な距離でWi-Fi接続をカバーする形にしました。 3つの周波数帯を用い、隣接するネットワーク機器の周波数帯を同じものにしないことで混線を避けました。

また、ネットワーク機器としてはAerohiveを導入しました。 Aerohiveを選定した理由は、グループ会社で既に安定して動いていた実績があったからです。

2. Kitting用の回線を作成

用途別に、3つの回線を用意しました。

アドレス 用途
固定IP① 社内用
固定IP② Kitting
DHCP割当 ゲスト

社内用とKitting用の回線を物理的に別にすることでKitting中でも速度低下などの影響を受けない環境になりました。

3. SSIDを統一

今までは執務室がConnehito Network1, 会議室がConnehito Network2という形でSSIDが複数ありましたが、 Aerohiveのローミング機能を利用して、上記の図の機器間で1つのSSIDを共有することができました。

実際に移転してみて

年明け初日から新オフィスでの営業でしたが、始業日から通常通り業務を始めることができ、ネットワークに関するトラブルはおきていません。 会社でインターネットが快適に使えるという“あたりまえ” を無事に提供することができたことは1つの成果なのではないかなと思っています。

移転作業に関わってくださった方々へ本当に感謝

今回の移転作業は3ヶ月という短い準備期間の中でメンバーやSyn.Holdingsの方々の助けもあり無事に達成することができました。 改めて関わってくださった皆様に感謝を申し上げます。

というわけで

快適なネット環境も手に入れたのであとはユーザーのためにプロダクトに向かうだけですね!今年も愚直に、粛々と頑張ります。 島田(@tatsushim)がお送りしました。

*1:初期環境構築に必要なソフトウェアのインストール

*2:無線LANにおけるアクセスポイントの識別名

YOKOSUKA IT Campで開発合宿を行いました

こんにちは、エンジニアの安達(@ry0_adachi)です。

この度、横須賀市が実施しているYOKOSUKA IT Campに参加して開発合宿をしてきました。
すごく良かったのでそのご紹介と、作ったものを報告しようと思います。

YOKOSUKA IT Camp

都内などのIT企業に、横須賀および横須賀リサーチパーク地区の認知度を高め、
将来的に事業拠点を置く候補地の一つとして認識していただけるよう、
横須賀市が実施する事業です。

都内のIT企業がオフサイトミーティングを横須賀リサーチパークで行う場合に、
必要な環境がすべて揃った会場を無料で提供します。

引用:YOKOSUKA IT Camp (http://www.yokosukaitcamp.com/)

横須賀の事をもっと知ってもらうための施策として横須賀市が実施しており、
合宿などで使用できる会場・設備を横須賀市が提供してくれる、というものです。

参加しようと思った経緯

年末くらいに開発合宿したい!となり会場候補を挙げていたのですが、その時に候補に挙がったYOKOSUKA IT Campの補助がすごい!となって、すかさず申し込むことにしました。
そして参加可能とのお答えをいただいて日程等の調整を進めていき今回の開発合宿に至りました。

横須賀市からの補助

今回、無料で提供していただけるものは

  • 横須賀市内の移動にマイクロバス
  • 合宿会場
  • 会場の横にある食堂でのお昼ご飯
  • 会場近くのホテル1泊分

と、何ともありがたい内容でした。ざっくりですが1人1万円くらい浮いたと思います。
また、合宿時のスケジュール作りなどもほとんどをやっていただきました。

1日目

  • 11:30 集合
  • 12:00 お昼ご飯
  • 13:00 開発
  • 19:00 晩ご飯
  • 22:30 開発

エンジニア・デザイナーの計8名で金曜日から日曜日にかけて行ってきました。
迎えのバスが来てくれるので久里浜駅に集合です。

開発会場が広い

f:id:dachi023:20170130182706j:plain

とにかく広かったです、8人で使うのがもったいないくらいでした。
作業時は写真の机を1人1つ使っていたのですが、それでもスペースが余っていたので空いた机に持ち寄ったお菓子とか飲み物を置いて使いました。
開発する場所としても室内のWi-Fiは研究施設などが入っている建物なので快適な通信速度ですし、電源は床から生えていて開発するにあたってストレスみたいなものは全くなかったです。

19時まで開発したあとは飲み会をして、終わってからは会場に戻って開発したり、ホテルに行って寝たり、各自が自由な時間を過ごしました。
ちなみに会場は24時間出入りできるので夜遅くまでやったり、朝早く起きた人は会場に来て開発したりしていました。

2日目

  • 12:00 お昼ご飯
  • 20:00 晩ご飯
  • 21:00 開発・発表資料作り

2日目は昼ご飯くらいまでには起きましょう、くらいのゆるい感じでスタートです。
ひたすら開発してた記憶しかないですが、みんな結構集中してて静かだったと思います。

美味しい牡蠣と蕎麦

f:id:dachi023:20170130194111j:plain

晩御飯は会場から徒歩5分くらいのところにあったお店に行きました。牡蠣の味噌焼丼と蕎麦が美味しかったです。あと、店員のおばちゃんがお茶目でした。

食べたあとは再度開発に戻り、最終日の発表に向けて追い込みをかける姿も見受けられました。私も開発するのが楽しくてひたすらコードを書いていました。

3日目

  • 10:00 成果発表
  • 12:00 横須賀中央駅へ移動
  • 13:00 お昼
  • 14:00 解散

いよいよ最終日、成果発表です。
発表開始ギリギリまで資料を作っている人もいました。

発表の順番決め

f:id:dachi023:20170130232405p:plain

ドカベンくじ引きで発表の順番を決めることにしました。
下記の記事を参考に実装しました。ありがとうございます。

qiita.com

成果物

1. 喋って音が鳴るBot, いでよBot

金城さん(@o0h_)の発表。

Slack上で sound!番号 と打つとBotを動かしているPCから番号に応じた音楽が鳴り、
これ読んで!読んでほしいテキスト とすると読み上げてくれます。
これはMac OSのafplaysayというコマンドを利用していて、MP3やテキストを再生する、というもの。音を出すのが楽しすぎて開発合宿が終わるまでみんな遊んでました。

そしてもう1つ、 いでよ!出てきてほしいもの と打つと登録していたものが出てくる機能。
複数行、スレッドにも対応していてslackbotの上位互換的な感じで使えそうです。

2. IntelliJプラグイン, Delegated Properties

富田さん(@tommykw)の発表。

Kotilin向けIntelliJプラグインとDelegated Propertiesのお話。
プラグインはAndroidのカスタムViewをKotlinぽくクイックフィックスしてくれるという便利なもので、こちらは完成までは至らなかったものの、Kotlinのソースコードを読んだりしてかなり知見が溜まったとのこと!IDEがないと生きていけないくらいにするため自ら貢献していく、と頼りになる言葉をいただきました。

Delegated PropertiesはKotlin標準の移譲のための仕組み。
継承するのではなく移譲することで処理の肥大化を防ぎましょうというのをママリQで実際に試した、という発表でした。

3. 妊娠月別の質問を用いたユーザ分類

CTO島田さん(@tatsushim)の発表。

ユーザ行動の分析を行うための基盤構築という難易度の高そうなものにチャレンジしていました。自然言語処理を扱うコアの部分の開発をされており、最終的にはプロダクトへの導入を検討しつつ、実際に形になったタイミングでブログやイベント等で発表するぞ!ということでした。続報に期待ですね!

4. Golangでmamari CLI

私(@ry0_adachi)の発表。

Golangでmamari CLIを実装しました。Golangの構文を覚えるところから始め、ママリ用のデプロイコマンドを作ることを目標に実装。
cobraというライブラリのおかげでシンプルな実装ができました。また、今回Golangで何かを作ったのは初めてだったのですが非常に良い言語だなぁと感じ、今後も使っていこうと思いました。

あとは、余った時間で前述のくじ引きやBotとかやったことを発表。開発合宿の時間をフル活用して色々できたので満足しました。

5. IoT知育玩具

きよえし(@kiyoe_furuichi)の発表。

可愛らしいウサギとネコのボタンを押すとディスプレイが切り替わる知育玩具です。
ウサギとネコとその土台はすべて裁縫をして作ったそうです、すごい…。
今後も子供に使ってもらえるような知育玩具をいろいろ作りたいと話していました。

発表時のスライドを上げてもらいました。 speakerdeck.com

6. 対話型Bot, ゴミ収集日リマインダ

高野さん(@fortkle)の発表。

メダロットが作りたくなったとのことで、Botkitでメタビーを実装。
docomoの雑談対話APIで雑談ができるようになっていました。

また、Botkitの対話モード(Conversations)を利用してアニメ版メダロットの名シーンを再現、ゴミ収集日をリマインダーに設定してくれる機能も実装されていました。
ゴミ出しは普通に便利そうなので真似しようかなと思っております。

7. Super Manner Mixer

結城さん(@super_manner)の発表。

Web Audio APIBeeplay.jsを使ってweb上で作曲ができるツールを作成。
画面上のボタンをポチポチやるだけで曲作れるのすごいです。

JavaScriptでこう言ったライブラリがあるということを知らなかったので勉強になったのと、そもそも作曲みたいなことがweb上の技術だけでできるんだなとびっくりしました。

8. エコー写真の検索アプリ

田村さん(@Utmrer)の発表。

エコー写真を妊娠週数ごとに閲覧可能なiOSアプリの作成。
Google Vision APIや検索結果などを駆使して週数ベースでエコー写真をカテゴライズし、それをリストで表示。
このアプリは同じ週数の方はどんな写真なのか、週数が進んだ時にどうなるのか、などの悩みを解決するためのアプリです。
アプリの技術的にはRxSwiftやXLPagerTabStripなどを利用し、実装したそうです。

実際にママさん達から上がった声からこういったものを作るのがすごくママリらしいなぁ、と感じました。

発表後

f:id:dachi023:20170202093313j:plain

発表が終わってからは横須賀市街へ行ってカレーを食べたり港沿いを散歩したりしてから解散となりました。初めての海軍カレーを食べましたがとても美味しかったです!

まとめ

というわけで、コネヒト開発部の開発合宿でした。
やるに当たって気をつけたこととしては

  • 開発に集中できる環境がある
    • Wi-Fi, 黙々と作業できる環境, 誘惑してくるもの(テレビとか)がない
  • なるべく拘束時間は減らして自由に開発する時間を増やす
  • 最後に発表を入れることで少しだけプレッシャーをかける

あたりを特に大事にしました。

また、全体的な感想として横須賀は非常に良い場所でした。ご飯も美味しかったですし、合宿会場も市街からは離れた場所なので静かですごく集中して3日間を過ごせました。
みなさんもぜひYOKOSUKA IT Campで開発合宿をやってみてはどうでしょうか。旅館などで行う合宿とはまた一風違った合宿になるかもしれません。

www.yokosukaitcamp.com

Cakeboxでお手軽CakePHP

f:id:supermanner:20170110152524p:plain

皆様、こんにちは! 今一番楽しみなのは 劇場版「Fate/stay night」Heaven's Feelであると言っても過言ではないエンジニアの結城(@super_manner)です!

さて、突然ですが現在私はCakePHP3を使ってAPI開発を行っています。

本エントリを読んでくださってるみなさまは普段どのような言語、フレームワークを使用されていますか?
体感として、近年私の周りでPHPをメインに開発されている方にはLaravelを使用されている割合が高いように思います。

日頃開発を行う中で、ふと「さっくり他のフレームワークを試してみようかな」と思うことはありませんか?
私の場合は、つい最近まではLaravelをメインに開発を行っていたので、CakePHP3を使用するにあたってあまりコストを掛けずに試すことができるものをもとめていました。

本日はお手軽にCakePHP3を試してみたいなと思った際にこういうのがあるよ!と言うものをご紹介します^^

Cakeboxとは?

Cakeboxは 「Multi-framework PHP development environment.」 を掲げていて, 少し前になりますが2015年からalpha版として世の中にリリースされています。

github.com

こちらの環境構築ツールを使用すると、Vagrant上に複数のframeworkで作成した複数のアプリケーションを走らせることが可能となっています。
デフォルトではCakePHP3が選択されており、オプションとして指定してあげることにより、2.x系やLaravel 5などのアプリを作成することができます!

実際の設定

設定はすべてCakebox.yamlに記載するだけで行うことができます。非常に簡単ですね!
詳しくはこちらの公式チュートリアルを見ていただくのが一番わかり易いです。
今回私が使用した設定は下記の通りです。

vm:
  hostname: cakebox
  ip: 10.33.10.10
  memory: 2048
  cpus: 1

cakebox:
  version: dev-dev
  debug: true
  https: false

git:
  username: my_git_user_name
  email: my.mail.address@hogehoge.com

security:
  box_public_key:
  box_private_key:

synced_folders:
  - local:  Apps
    remote: /home/vagrant/Apps

apps:
  - url: mycake3.app
  - url: mylaravel.app
    options: --framework laravel

vhosts:

databases:

extra:
  - apt_packages:
    - vim
    - zsh
    - language-pack-ja

  - scripts:

特殊な設定はしていませんが、私は普段の開発環境がvimとzshなのでextraにpackageを追記しておきました。
また、ゲストマシンにログイン時、言語設定のwarningが出るのが鬱陶しかったので、日本語のランゲージパックも入れておきました。

気になった点など

先述したとおり、Cakeboxは本当に簡単に設定できます。 しかしながら、幾つか設定中にうまくいかなかった部分や、迷った部分があるので共有させていただきたいと思います。

Laravelのアプリケーションが入らなかった

実ははじめに設定ファイルをいじって作ったり壊したりしている際に、時々エラーが出てLaravelを入れる部分で落ちてしまうケースがありました。
原因としてはmemory不足であったようです。 なので、Cakebox.yamlのvmセクションでmemoryの量を増やしました。
1024がデフォルトのところを2048にしています。

hostsの設定はどうなっているのか

Cakebox.yamlに特に何も設定していない場合vhostsの設定はどうなっているのかな?と思い見てみました。 *1
Cakeboxはdashboardから様々な設定を確認することができます。dashboardはデフォルトで 10.33.10.10 にアクセスするとみることができます。 最初にuserとpasswordを聞かれますが、何も入れなくて大丈夫です^^;

f:id:supermanner:20170110152847p:plain:w400 f:id:supermanner:20170110152854p:plain:w400

上図を見ていただくと、アプリケーション名をとってvhostsの設定がされているのがわかります。 実態としては /etc/nginx/nginx.conf に下記のように記載されていますので、

http {
  (中略)
        # virtual hosting
        include /etc/nginx/sites-enabled/*;
}

/etc/nginx/sites-enabled/* を見に行くと...

vagrant@cakebox:/etc/nginx/sites-available$ ls
default  mycake3.app  mylaravel.app

アプリケーションの名前で設定ファイルが作られていることが確認できました!
至れり尽くせりですね(^^)

感想・おわりに

業務で必要になった等で本格的に使用していく前にさっくりと新しいフレームワークを試したい場合等に、環境構築は意外と面倒なものだったりします。
今回ご紹介したCakeboxを使用すれば例えば慣れ親しんだLaravel製アプリケーションを動かしながら、CakePHP3で書いてみるとどうなるのだろうと言った使い方が可能です。

Cakeboxはまだまだ開発途中のようなので、私もなにかしらで貢献して行きたいなと思います。 そしてCakePHPユーザーが周りに増えてくれれば知見も溜まっていいぞ!!!と心のなかで思っています。

*1:各アプリケーションにアクセスするためにはローカルマシンのhostsを設定してください http://cakebox.readthedocs.io/en/latest/tutorials/creating-your-first-website/#3-update-your-hosts-file