Wondershake 開発者ブログ

LOCARI(ロカリ)の運営会社の開発者ブログです。

非iOSエンジニアが、iOSDC Japan 2016に当日スタッフで参加してきた

去る2016年8月19日&20日、iOSDC Japan 2016が開催されました。
記念すべき第1回目で、TrackBのTK(タイムキーパー)&司会を担当しました、安藤です。

「ブログを書くまでがiOSDC」By@tomzohさん・・・ということで。
今回は、iOSDC Japan 2016に参加するメリットと、スタッフをやった感想について書きます。 f:id:kikoando:20160926233832j:plain

iOSDC Japan 2016とは?

「iOSDC (iOS Developers Conference Japan) は、
iOSとその周辺技術に関するエンジニアのためのカンファレンスです。
iOS関連のカンファレンスを待っていた皆様、お待たせしました。ついにやってきました。

2016年8月20日はiOSエンジニアのお祭りです!
日本中、世界中から公募されたスピーカーがキレッキレのトークを繰り広げます。
トークは「iOSエンジニアが聞いて面白ければ何でもOK」という基準で選定されます。
iOSやSwiftといった王道テーマから、エモい話、デザインの話などもあるかもしれません。

そして、トーク終了後には同じ会場で懇親会が開催されます。

iOSDCはiOSエンジニアであれば誰でも楽しめるカンファレンスです。
皆様のご参加をお待ちしています。
カンファレンス未体験の方も、是非一度参加してみてください。
楽しく、エキサイティングな、忘れられない1日になるでしょう!」

公式サイトより。)

実際、トークの内容は

  • Swift誕生から現在までの軌跡を振り返る王道トーク
  • 個人の経歴をネタにしたトーク
  • アイコンデザインに関するトーク

さらにはコードに全く関係ない肉トーク(!)まで多岐に渡っていました。

※トークの内容は→こちらをどうぞ。

内容のバラエティさもさることながら、
イベント全体を包む空気がまさに「祭り」でした。 f:id:kikoando:20160926234602j:plain

そもそもなぜiOSDCの当日スタッフやろうと思ったの?

ことの始まりは、2016年7月11日。
こんなツイートが。

「イベントの運営経験値を貯めたい。iOSのことを知りたい」
そう思っていた自分には最高の機会だな。ということで、参加表明しました。

締め切り後、当選のメールが来てiOSDCスタッフSlackに招待され
その後は基本Slack上でやりとりをして当日を迎えます。

(8月16日に事前スタッフ顔合わせがありましたが、私は台風の影響で行けませんでしたorz)

参加者のメリット

  • 国内外で活躍されているエンジニアのトークが聞ける
  • 聞くだけじゃなくて、一問一答も出来る
  • 一問一答だけじゃなくて、会話もできる
    (スピーカーに話しかけるタイミングは沢山あります。
     普通に会場内をウロウロしています。懇親会なんて絶好のチャンス)
  • 充実したノベルティ、ビール← f:id:kikoando:20160926233948j:plain f:id:kikoando:20160926235446j:plain f:id:kikoando:20160926234003j:plain

結果

  • 新しい知見が手に入る
  • 悩んでいた問題が解決する
  • 開発へのモチベーションが上がる
  • 技術だけじゃなく働き方の指標にも出会える
  • ごきげんになれる(ビールでなれる人は)
  • 交流の輪が広がる f:id:kikoando:20161002215529j:plain

スタッフのメリット(主観)

  • 楽しい。仲間ができる。 f:id:kikoando:20160926234849j:plain

一言で言うと、これに尽きます。

実際に私がやったこと

1日目

時間の大半を机と椅子の設営に費やしました。
プロジェクターやカメラもほぼセッティングし終えたところで二手に分かれてみんなでランチ。

戻ってきてから、GitHubで配布されていたマニュアルを漁ります。
同じチームリーダーの@koogawaさんと打ち合わせしつつ
アナウンスの練習をしたら、あっというまに開場の時間。
この日はTrackBのTKが自分一人だったので、ずっとスピーカーと時間を気にしてました。
f:id:kikoando:20161002215717j:plain

最後のトークセッションを終えたら、受付に出てたシャツ等を部屋の中に入れ、
そそくさとスピーカーディナー(という名の飲み会)へ。

2日目

TrackBのTKが2人になったので、昨日より余裕が出てきました。
ただ、冷暖房や電気の明るさ調整など、気は抜けません。

この日は、後半TrackAと部屋を結合してからずっと懇親会の設営のことで頭がいっぱい。
1日目に3-4時間かけて並べた机と椅子を、30分で片付けるスケジュールでしたから。。。
実際は・・・スタッフのみなさんの協力のもと、スイスイことは進みました。 f:id:kikoando:20161002212825j:plain

懇親会では、ビールと料理を手に談笑する参加者&スピーカー&スタッフの皆さんを
端から見ては「みんな楽しそうだな。良い光景だな」と思ってました。 f:id:kikoando:20160926234016j:plain

さて、当日スタッフをやると、持ち場によってはほぼトークが見れなかったり(※)します。
また、コアスタッフは前日までの準備に何十時間という時間を費やします。
頭も体も使うから、どっと疲れる2日間です。

※配信管理やHQをされていたiOSエンジニアスタッフさんが「この人のプレゼン参考になるわ〜」とか「あ、そういうやり方あるのね〜」と漏らしてたので、見てなかったのは私だけかもしれません\/(トークは後ほど動画で配信されるので、見れなくても大丈夫ですが!)

でも、この祭りの楽しさを一番享受していたのはコア&当日スタッフだったのではと思います。
某スタッフさんも「こんなに楽しかったのは本当に久しぶり」と言ってましたしね!
みんなでひとつひとつ創っていく様子は、学生時代の文化祭準備を想起させてくれました。 f:id:kikoando:20161002214828j:plain

結果

もっとiOSのことが好きになりました。 f:id:kikoando:20160926234052p:plain (9/14の振り返りMTG後。ごきげん過ぎて画面に収まりきらない)
実際、私はiOSエンジニアではなかったのですが。この後、他のスタッフ主催の勉強会に参加したりして、iOSの世界に足を踏み入れかけています。

・・・iOSDC japan 2016が最高なイベントだったことは伝わりましたでしょうか。
少しでも楽しそうだと思った方は、来年のイベントスタッフ運営してみませんか?
スタッフになる方法?コアスタッフなら、@tomzohさんに聞いてみてください!
当日スタッフなら、きっと来年も公開応募があるかも?公式サイトとツイッターを要チェック!

まとめリンクたち

スピーカーや参加者、他のスタッフのブログはこちら
写真で振り返るiOSDC Japan 2016はこちら
トークセッションの映像はこちら

ここでちょっとお知らせ

11/11(金):ポッキーの日にエンジニア勉強会(もくもく会)を開催します。
もくもく内容は、何でもあり!前回は、お仕事する人や読書する人などもいらっしゃいました。

普段一人で家やカフェでもくもく作業してる人、11/11はみんなでもくもくやりませんか?
最初に今日何をもくもくするかを共有するので(任意)、きっと捗りますよ! daikanyama-mokumoku.connpass.com

また、WondershakeではiOSエンジニアを絶賛募集中です。
(無理に「来年一緒にiOSDCのスタッフやろう」とは言いません。)
一緒に会社を盛り上げてくれる方、Wanted。 www.wantedly.com

最後に

@tomzohさん、リードありがとうございました&大変お疲れ様でした!
f:id:kikoando:20161002215547j:plain

ProGuard Tips

こんにちは。Androidアプリを開発している代蔵です。 今回はアプリのサイズを削減するのに欠かせないツールProGuardに関する簡単なTipsを書いてみました。

アプリのサイズ

近頃、RxJavaやRetrofitなどAndroidアプリの開発に欠かせない便利なライブラリが増えてきています。こういったライブラリにより、開発速度・メンテナンス性は改善されている一方で、アプリの容量が大きくなってしまうという弊害が有ります。 この対策として、一般的にはProGuardを利用してアプリのサイズを小さくします。他にもredexといったツールを使うことでアプリの容量を小さくすることも可能です。

ProGuard

ProGuardを簡単に説明すると、使われていないクラスやメソッドを削除したり、クラス名やメソッド名などを難読化するためのツールです。これを利用することでコード量が削減されるので相対的にアプリケーションの容量が小さくなります。 ProGuardを利用する場合は以下のコードをbuild.gradleに追加し、proguard-rules.proに難読化したくないクラス名などを記述することで、ライブラリ内のクラス名などが削除・難読化されないようになっています。大抵のライブラリはProGuard用の設定を書いてくれています。

minifyEnabled true

ここで問題になるのは、利用するライブラリが増えれば増えるだけproguard-rules.proに記述する量が増えるので、可読性や管理コストが上がってしまいます。 例えば以下の様に一つのファイルに、様々なライブラリのルールを記述していくと管理するのが大変になっていきます。

# Retrofit
-dontnote retrofit2.Platform
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions

# Picasso
-dontwarn com.squareup.okhttp.**

# OkHttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**

# RxJava
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
   long producerIndex;
   long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

# ButterKnife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }

-keepclasseswithmembernames class * {
    @butterknife.* <fields>;
}

-keepclasseswithmembernames class * {
    @butterknife.* <methods>;
}

proguard-rules.proを分割する

Locariでは、ProGuard用のルールをそれぞれのライブラリに対して作成することで管理を楽にしています。具体的には、proguard-rulesというディレクトを作成し、その中に各種ライブラリ用のルールを記述し、gradleでそのディレクトリの中身を読み込むような形にすることで、ルールファイルを分割しています。

proguardFiles getDefaultProguardFile('proguard-android.txt')
proguardFiles fileTree(dir: 'proguard-rules', include: ['*.pro']).asList().toArray()

f:id:takumiumiu:20160905153651p:plain

雑感

最近のライブラリはProGuardでkeepしなくても良いものが増えてきていますが、ルールとして記述しないといけないものが依然としてあるなか、このように管理するのは意外と便利です。 みなさんもぜひお試し下さい!

加えて、毎回書いていますが弊社ではAndroidiOS、サーバサイドエンジニアを絶賛募集しています。 ご興味の有るかた是非ご応募下さい! :)

https://www.wantedly.com/projects/60449

Rails 5 のマイナー機能の紹介

こんにちは、バックエンドエンジニアのダイクストラです。

Rails 5 がやっと出ました!ActionCable やTurbolinks 3など大きな機能が色々追加されました。 加えて,Ruby 2.2.1以上を使うことが必要になりました。 これらに関する記事はたくさんあるので、今回はあまり知られていない機能を紹介します。

便利な機能

APIベースのアプリケーションが作成可能

人気のジェム Rails APIRails 5 にマージされました。ActionController::APIAPI のみのアプリケーションを作成することが出来ます。新しいアプリケーション作る時、フラグを追加するだけで出来ます。

rails new hogehoge --api

このタイプのアプリケーションは、ActionController::Base ではなく、ActionController::API を使います。middlewareも少なくなり、コントローラーがもっとシンプルになるので、JSベースのアプリ作る時は、このような作り方が便利です!

PRリンク

Migration に コメントを追加できる

データベースにはあった機能ですが、今まで直接SQLのクエリで書く必要がありました。Rails 5 から MySQLPostgreSQL 使っていれば、コメントを追加することができます!

class CreatePosts < ActiveRecord::Migration[5.0]
  def change
    create_table :posts, comment: 'テーブルのコメント' do |t|
      t.string :title, comment: 'フィールドのコメント'
    end
  end
end

DBAのツールにも、schema.rbにもコメントでます。

PRリンク

create_join_table で UUID を使える

これはシンプルな機能ですが、今までは integer を扱えませんでした。

class CreateJoinTableFavorites < ActiveRecord::Migration[5.0]
  def change
    create_join_table(:users, :posts, column_options: {type: :uuid})
  end
end

PRリンク

使わないで欲しい機能

ActiveSupportArray#second_to_lastArray#third_to_last のメソッドが増えた

よく .last.first を使うと思ますが、 third_to_last などは本当に必要ありますか?マジックナンバー)のようなものなので、先にリファクタリングして欲しいです。Array 使わず Hash にすれば、コードが分かりやすくなる可能性があります。どうしてもこの使い方しかないと思ってたら、普通に Array[-2] 是非、使ってください。

PRリンク

ActiveSupportEnumerable#without のメソッド増えた

Array の場合は ary1 - ary2 でこれが実現できますし、Hash の場合は色んなやり方があるので、不必要なメソッドが増えたと思います。

Rubyの標準ライブラリで簡単に書けることをわざわざRailsだけのコードで書く意味がないです!

> [1,2,3,4,5] - [3,4]
=> [1, 2, 5]
> {a: 1, b: 2, c: 3}.reject{|x| [:a].include? x}
=> {:b=>2, :c=>3}

PRリンク

ActiveRecord のオブジェクト をsave する時、(touch: false) を入れれば、 updated_at はアップデートされない

今まで save した時、 updated_at がアップデートされたのに、急に touch: false をつけてしまうと、挙動が変わるので同じプロジェクトで働いてる人が困惑する可能性があります。save(touch: false) を使いたい時は、updated_at ではなく、新しいコラム作ったほうがいいでしょう。

PRリンク

その他の便利なアップデート

SQLのログにカラーが増えた

f:id:dykstra:20160817181904p:plain

PRリンク

アプリからログをいい具合にBigQueryに突っ込む険しい道

千葉です。基盤と雑用をしています。

弊社のログの解析はBigQueryに丸投げなのですが、それ以外はAWSさんにおんぶにだっこなので、いわゆる

  • Kinesis Firehoseからかんたんに Redshift にはいります!!
  • Mobile Analyticsからボタンひとつで Redshift にはいります!!

というのを敢えて使わずに茨の道を歩まねばなりません。辛いです。 また、BigQueryのStreaming Insertで100%安心です\(^o^)/ となれば良いのですが、前に障害のメールもありましたし、デバッグもしにくいという理由からこちらも避けて通っています。

ということで弊社の構成です。

  1. アプリはMobile AnalyticsのSDKを使ってログをいい具合に転送する
  2. Mobile AnalyticsのS3連携(Kinesis Firehoseのよう)で定期的にS3に書き出す
  3. Lambda が S3 Put Event を拾って DynamoDB に記録しつつ BigQuery に突っ込むjobをつくる

最近は俄然Kinesisファミリーが流行していますが、Mobile Analyticsも同じようなことができます。 また Cookpadさんのpureeのようなものがアプリではやはり必要なので、AWSさんの開発力に乗ってしまえるのも利点です。

ところが、いきなりの障害

上記の運用でしばらくうまくいっていたのですが、急にログがBigQueryにはいらなくなりました/(^o^)\ よくよく見ると Put のイベントの数がいきなり増えています。

f:id:tachiba1207:20160818050513p:plain

BigQueryはテーブル毎に1日に Insert する Job を作れる制限が決まっており、それが1,000件になっています。 それを超えてしまい、どうしようもなくなった!という状態でした。

仕方ないのでログを結合する

幸い、どのログが入ったのか入っていないのか、BigQueryのJobのIDがなんなのかというのはLambdaからDynamoDBに記録していたので、たどることができます。

なので、うまい具合にretryもしつつ、S3にたまったログを結合して(且つ、timestampなど特定のカラムをnormalizeして)BigQueryにいれるスクリプトを書きました。書きましたとも!

うまくいった

ということで、上記の対応でうまく対処できました。こうやって日々Locariのログを捌いています。

BigQueryはデータの投入もとても早いので(Steraming Insertの場合もすぐクエリーをうてます)かなりリアルタイムに近いデータにアクセスができるのは利点かなと思っています。もちろんBIのBackendとしても十分な速度とコストパフォーマンスがあると思います。

ちなみに汎用化すれば、BigQueryの普及に寄与できそうな Lambda(ES2015) を公開できそうなのですが、もうしばらく時間がかかりそうです...!

このスクリプトのメンテを中心とする基盤のメンテナンスやBigQueryに向けて一緒にクエリーを叩いてくれるような方を探しています! よかったらご応募ください!

jobs.lever.co

アイコンフォントライブラリを使ってみる

こんにちは、iOS開発担当の藤井です。

iOSアプリの開発を行うときにちょっと面倒なのがアイコン画像ファイルの追加だったりします。画像を切り出して、Images.xcassetsに1x, 2x, 3xをそれぞれ追加して… 特にモックレベルのものを作るときは、そもそもアイコン画像がなかったりするので自分で用意するとなると相当大変です。

先日の記事でも紹介したIoniconsiOS/Androidアプリ内で利用頻度が高そうなアイコンをカスタムフォントとして利用できるフォントライブラリです。

まずはインストール方法ですが、IonIconsはCocoapodsで配信されているのでいつものようにPodfileに以下を追加します。

pod 'ionicons'

UIImageとして利用したい場合は、

UIImage *icon = [IonIcons imageWithIcon:ion_ionic
                                  iconColor:[UIColor redColor] 
                                   iconSize:60.0f 
                                  imageSize:CGSizeMake(90.0f, 90.0f)];

という感じでUIImageとして生成します。色やサイズなども同時に指定可能です。 ただあくまでもアイコンフォントなので単色のみでしか指定できないので注意が必要です。 'ion_ionic'の部分はサイトから使いたいアイコンをホバーすると出てきます。'ion_ios_arrow_back'や'ion_ios_search'といったよく使いそうなアイコンから、'ion_social_twitter'や'ion_social_facebook'といった地味に便利なアイコンまでたくさんそろっています。

f:id:penpen-0704:20160803021212p:plain

UIImageだけでなくUILabelとしても利用できます。

UILabel *label = [IonIcons labelWithIcon:ion_ionic size:20.0f color:[UIColor blackColor]];

という形で生成してあげればOKです。

また、カスタムフォントなので文中に混ぜるといったことも可能です。例えばLocariでは記事一覧画面でのお気に入り数の横にあるハートアイコンをその方法で追加しておます。

これは

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ %@", ion_ios_heart_outline, likeCount]];

[attributedText addAttributes:@{NSFontAttributeName:[IonIcons fontWithSize:13]} range:NSMakeRange(1, 1)];

cell.likeLabel.attributedText = attributedText;

という感じにstringWithFormatなどで連結してあげて、NSFontAttributeNameでIonIconsを該当箇所に指定するとうまい具合に反映されます。

f:id:penpen-0704:20160803024032p:plain

文字内に含むのは若干レアケースかもしれないのですが、覚えておくと何かと便利かもしれません。

このようにLocariではIonIconsを利用しているのですが、もちろんこれ以外にもたくさんのフォントライブラリがあり、まとめて入れたい場合はFontAwesomeKit辺りを入れると便利なので気になる方はこちらも検討してみてください。

またSwiftの場合は別な方がSwift版をCocoapodsで配布しているので、そっちを利用すると良さそうです。

またWondershakeではアイコンフォントライブラリを使いこなせるiOSエンジニアも募集中です。 www.wantedly.com

RailsアプリケーションのためのフロントエンドLint環境の整備(SCSS編)

こんにちは。フロントエンドエンジニアの佐々木です。

前回は JS 周りの Lint 環境を整備しました。

engineering.wondershake.com

今回はスタイルシート周りの Lint 環境を整備した話になります。

はじめに

スタイルシートはある程度のルールをチーム内で共有しておかないとすぐに雑多なコードになってしまいます。

コーディングルールを明文化してレビューで指摘するといった方法もありますが、できれば Lint ツールでコーディングスタイルを定義して、ルールに逸脱したコードは CI で落とすようにすると健全です。

今回は 2 年間運用されてきた scss ファイルに scss-lint を実行して、エラーを 0 にして CI で弾くことができる状態にするのがゴールになります。

なお scss-lint を導入するにあたりこちらの記事を参考にさせて頂きました。

自動検出と自動修正でCSSを保守する - Qiita

scss-lint

f:id:sskyu:20160725165603p:plain

インストール

scss-lint の Installation を見ると、

$ gem install scss_lint

でインストールするか、Gemfile に

gem 'scss_lint', require: false

を追記して bundle install することでインストールできます。

依存する gem は Gemfile に書いておきたいので、後者でインストールしました。

scss-lint を実行してみる

実行するには下記のコマンドを実行します。

$ bundle exec scss-lint app/assets/stylesheets/**/*.scss
app/assets/stylesheets/admin.scss:1:1 [W] Comment: Use `//` comments everywhere
app/assets/stylesheets/admin.scss:10:9 [W] StringQuotes: Prefer single quoted strings
app/assets/stylesheets/admin.scss:11:9 [W] StringQuotes: Prefer single quoted strings
# 以下膨大なエラーメッセージが続く

エラーが多すぎて原因がよくわからないので、オプションに --format=Status を付けてもう一度実行します。

$ bundle exec scss-lint --format=Stats app/assets/stylesheets/**/*.scss
 257  PropertySortOrder              (across 58 files)
 217  SpaceBeforeBrace               (across 58 files)
 175  NameFormat                     (across 46 files)
 154  StringQuotes                   (across 67 files)
 102  SelectorDepth                  (across 23 files)
  93  NestingDepth                   (across 28 files)
  75  QualifyingElement              (across 31 files)
  65  ColorVariable                  (across 31 files)
  59  EmptyLineBetweenBlocks         (across 21 files)
  47  SpaceAfterPropertyColon        (across 16 files)
  39  DeclarationOrder               (across 17 files)
  35  Shorthand                      (across 23 files)
  35  IdSelector                     (across 17 files)
  34  ColorKeyword                   (across 22 files)
  32  LeadingZero                    (across 11 files)
  30  PseudoElement                  (across  7 files)
  27  FinalNewline                   (across 27 files)
  26  SpaceAfterComma                (across  2 files)
  21  ImportantRule                  (across 11 files)
  19  Indentation                    (across  7 files)
  16  SelectorFormat                 (across  9 files)
  16  BorderZero                     (across 10 files)
  14  VendorPrefix                   (across  3 files)
  14  SingleLinePerSelector          (across  9 files)
  12  Comment                        (across  7 files)
  12  ZeroUnit                       (across  7 files)
   5  EmptyRule                      (across  4 files)
   4  UnnecessaryMantissa            (across  1 files)
   4  MergeableSelector              (across  3 files)
   3  TrailingSemicolon              (across  3 files)
   3  PlaceholderInExtend            (across  1 files)
   1  SpaceBetweenParens             (across  1 files)
   1  SpaceAfterVariableName         (across  1 files)
----  -----------------------        -----------------
1647  total                          (across 91 files)

今のところ 91 ファイルに渡って 1647 個のエラーがあることが分かります。

デフォルトでどんなルールが設定されているかというのはこちらのドキュメントにまとまっています。

scss-lint/README.md at master · brigade/scss-lint · GitHub

ここからエラーを 0 にする修正を行っていきます。

scss-lint.yml を作成する

デフォルトの設定だとかなり厳しいルールになっているので、幾つかのルールを無効化するように設定することにします。

プロジェクトルートに .scss-lint.yml を作成し、ドキュメントを見ながらルールを無効化していきます。

この段階ではこのような .scss-lint.yml が出来上がりました。

scss_files: 'app/assets/stylesheets/**/*.scss'

exclude: 'app/assets/stylesheets/lib/**'

linters:
  BorderZero:
    convention: none

  ColorKeyword:     # ルール名に対して
    enabled: false  # enabled: false を指定して無効化する

  ColorVariable:
    enabled: false

  Comment:
    enabled: false

  DeclarationOrder:
    enabled: false

  EmptyLineBetweenBlocks:
    enabled: false

  IdSelector:
    enabled: false

  LeadingZero:
    enabled: false

  NameFormat:
    convention: '^[a-z][-a-z0-9_]*$'

  NestingDepth:
    max_depth: 4

  PropertySortOrder:
    enabled: false

  QualifyingElement:
    allow_element_with_attribute: true
    allow_element_with_class: true

  SelectorDepth:
    max_depth: 4

  Shorthand:
    enabled: false

  SpaceBeforeBrace:
    allow_single_line_padding: true

  StringQuotes:
    style: double_quotes

設定ファイルを作った状態で scss-lint を実行してみます。

$ bundle exec scss-lint --format=Stats
217  SpaceBeforeBrace               (across 58 files)
 62  StringQuotes                   (across 12 files)
 47  SpaceAfterPropertyColon        (across 16 files)
 32  NestingDepth                   (across 13 files)
 30  SelectorDepth                  (across 10 files)
 30  PseudoElement                  (across  7 files)
 27  FinalNewline                   (across 27 files)
 26  SpaceAfterComma                (across  2 files)
 21  ImportantRule                  (across 11 files)
 19  Indentation                    (across  7 files)
 16  SelectorFormat                 (across  9 files)
 14  SingleLinePerSelector          (across  9 files)
 14  VendorPrefix                   (across  3 files)
 12  ZeroUnit                       (across  7 files)
  5  EmptyRule                      (across  4 files)
  4  UnnecessaryMantissa            (across  1 files)
  4  MergeableSelector              (across  3 files)
  3  NameFormat                     (across  1 files)
  3  TrailingSemicolon              (across  3 files)
  3  PlaceholderInExtend            (across  1 files)
  2  BorderZero                     (across  2 files)
  1  SpaceAfterVariableName         (across  1 files)
  1  SpaceBetweenParens             (across  1 files)
---  -----------------------        -----------------
593  total                          (across 77 files)

ソースを変更せず、ルールを緩くしたことで 593 まで減りました。

csscomb で自動フォーマットする

f:id:sskyu:20160725174344p:plain

上記出力結果の 217 SpaceBeforeBrace (across 58 files)154 StringQuotes (across 67 files) などは簡単な修正で直りそうです。
人間の手でやると間違ってしまう可能性があるので、ツールを使ってやると良いでしょう。

csscomb を使うとスタイルシートの自動フォーマットをすることができます。

CSScomb: Makes your code beautiful

インストール

csscombは npm で提供されているので、node.js がインストールされている必要があります。

開発時に使うモジュールなので -D (--save-dev) を付けてインストールします。

$ npm i -D csscomb

csscomb用の設定ファイルの作成

csscomb を使い、どのようにフォーマットするのか指定するための設定ファイルを作ります。

下記のページからどのようにフォーマットしたいか、選択形式で作ることができます。

CSScomb: Build config

f:id:sskyu:20160725175703p:plain

例えば一番初めの選択肢の場合、Remove empty rulesets を有効にするかどうかを聞かれています。
有効にする場合は左のコードをクリックして、無効にする場合は右のコードをクリックします。
これを 24 つ続けていくと .csscomb.json のサンプルコードが表示されるので、このコードをコピーしてプロジェクトルートに .csscomb.json を作成しましょう。

作成したら下記コマンドで実行します。
(※ 大量の scss ファイルの差分が発生するのでここまでの作業をコミットしておくと良いです。)

$ ./node_module/.bin/csscomb app/assets/stylesheets/**/*.scss

コマンドが長いので package.json の scripts に登録しておきます。

  scripts: {
     "format:scss": "csscomb app/assets/stylesheets/**/*.scss"
  }

これで $ npm run format:scss で csscomb が動くようになりました。

いくつかの調整をして、.csscomb.json はこのような形になりました。

{
  "exclude": [
    "node_modules/**",
    "app/assets/stylesheets/lib/**",
    "app/assets/stylesheets/shared/colors.scss",
    "app/assets/stylesheets/web/mixins/z_indexes.scss"
  ],
  "always-semicolon": true,
  "color-case": "lower",
  "block-indent": "  ",
  "color-shorthand": true,
  "element-case": "lower",
  "eof-newline": true,
  "leading-zero": true,
  "quotes": "double",
  "space-before-colon": "",
  "space-after-colon": " ",
  "space-before-combinator": " ",
  "space-after-combinator": " ",
  "space-between-declarations": "\n",
  "space-before-opening-brace": " ",
  "space-after-opening-brace": "\n",
  "space-after-selector-delimiter": "\n",
  "space-before-selector-delimiter": "",
  "space-before-closing-brace": "\n",
  "strip-spaces": true,
  "tab-size": true,
  "unitless-zero": true
}

csscomb によるフォーマットを適用した状態で scss-lint を実行してみます。

$ bundle exec scss-lint --format=Stats
 32  NestingDepth                  (across 13 files)
 30  SelectorDepth                 (across 10 files)
 30  PseudoElement                 (across  7 files)
 26  SpaceAfterComma               (across  2 files)
 21  ImportantRule                 (across 11 files)
 16  SelectorFormat                (across  9 files)
 14  VendorPrefix                  (across  3 files)
  5  EmptyRule                     (across  4 files)
  4  MergeableSelector             (across  3 files)
  4  UnnecessaryMantissa           (across  1 files)
  3  PlaceholderInExtend           (across  1 files)
  3  NameFormat                    (across  1 files)
  2  BorderZero                    (across  2 files)
  1  SpaceAfterVariableName        (across  1 files)
  1  SpaceBetweenParens            (across  1 files)
---  ----------------------        -----------------
192  total                         (across 35 files)

フォーマットをして 192 個までエラーが減りました。

エラーを 0 にするまでの作業

ここからは地道に修正していくしかありません。

特別にやったことといえば、 VendorPrefix のルールに適合するため、autoprefixer-rails をいれて、ベンダープレフィックスは自動生成されるようにしたことくらいでしょうか。

GitHub - ai/autoprefixer-rails: Autoprefixer for Ruby and Ruby on Rails

特に難しかったのが NestingDepthSelectorDepth のルールをパスすることでした。

初期のソースは何故かネストが深い箇所が多々あり、まずはネストを一段下げてスタイル崩れが起きないか確認を頻繁に行いました。
ネストが深いとスタイルを上書きしたい場合にやりづらかったり、出力される css ファイルのサイズが肥大化したりと良いことがありません。
詳細度を上げてスタイルを作るよりも、クラス名にユニーク性を持たせてネストを下げるようにするべきです。

結局、設定で depth: 4 を指定しましたが、止むを得ず depth: 5 を指定して修正することになりました。

色々な妥協を経て、.scss-lint.yml はこのようになりました。

scss_files: 'app/assets/stylesheets/**/*.scss'

exclude: 'app/assets/stylesheets/lib/**'

linters:
  # border: 0 -> border: none
  BorderZero:
    convention: none

  # color: white などの利用を禁止
  ColorKeyword:
    enabled: false

  # color: $body-color のように変数を強制する
  ColorVariable:
    enabled: false

  # /* */ でのコメントを禁止
  Comment:
    enabled: false

  # @extend, @include, @content の記述順をスコープの先頭に強制する
  DeclarationOrder:
    enabled: false

  # ルール間に改行を強制する
  EmptyLineBetweenBlocks:
    enabled: false

  # 空のルールを禁止する
  EmptyRule:
    enabled: false

  # IDセレクタに対するスタイル付けを禁止する
  IdSelector:
    enabled: false

  # !importantを禁止する
  ImportantRule:
    enabled: false

  # opacity: 0.5 -> opacity: .5
  LeadingZero:
    enabled: false

  # 変数名の命名規則を定義する
  NameFormat:
    convention: '^[a-z][-a-z0-9_]*$'

  # ネストの深さを制限する (default: 3)
  NestingDepth:
    max_depth: 5

  # プロパティの記述順を強制する
  PropertySortOrder:
    enabled: false

  # div.selector などの書き方を制限する
  QualifyingElement:
    allow_element_with_attribute: true
    allow_element_with_class: true

  # セレクタの深さを制限する (default: 3)
  SelectorDepth:
    max_depth: 5

  # セレクタの名前のルールを定義する (default: hyphenated_lowercase)
  SelectorFormat:
    ignored_names:
      - 'fb_iframe_widget'  # facebook widget
      - 'field_with_errors' # generated by rails
    ignored_types:
      - 'id'

  # color: #ff0000 -> color: #f00 のように短い記述を強制する
  Shorthand:
    enabled: false

  SpaceAfterComma:
    exclude:
      - 'app/assets/stylesheets/shared/colors.scss'

  # p{} -> p {} のようにスペースを強制する
  SpaceBeforeBrace:
    allow_single_line_padding: true

  SpaceBetweenParens:
    exclude:
      - 'app/assets/stylesheets/shared/colors.scss'

  # 文字列を表すクォートの種類を指定する (default: single_quotes)
  StringQuotes:
    style: double_quotes

  # 必要のないvendor-prefixの記述を禁止する
  VendorPrefix:
    enabled: false

この状態で scss-lint を実行します。

$ bundle exec scss-lint --format=Stats
$

何も出力が表示されないということで、エラーを 0 にすることができました。

scss-lint を npm scripts に登録する

CI で実行するときに、npm test を叩けばフロントエンドのテストが走る状態にしたいので、bundle exec scss-lint も npm scripts に登録しておきます。

前回の内容も含めると、下記のようになります。

  "scripts": {
    "format:scss": "csscomb app/assets/stylesheets/**/*.scss",
    "test": "npm run test:lint",
    "test:lint": "npm run test:eslint && npm run test:coffeelint && npm run test:scsslint",
    "test:eslint": "eslint --ext .js,.jsx app/assets/javascripts",
    "test:coffeelint": "coffeelint -f .coffeelint.json app/assets/javascripts",
    "test:scsslint": "bundle exec scss-lint"
  },

これで最低限の品質を担保する仕組みが整いました。

おまけ

エディタに Lint 環境を整備する

私は ATOM Editor を使っているのですが、エディタが各種 Linter に対応しているとリアルタイムにエラーを報告してくれて便利なので是非設定しましょう。

ATOM に linter-scss-lint をセットアップする

まず linterlinter-scss-lint というパッケージをインストールします。

インストールしたら linter-scss-lint の Setting を開きます。

(ここからは ruby のバージョン管理に RVM を利用している場合の紹介になります。)

公式ドキュメントにある通り、まず scss-lint コマンドが使えるようになっている必要があります。

$ gem install scss_lint

次にコマンドのパスを取得します。

$ which scss-lint
/Users/sasaki_yutaka/.rvm/gems/ruby-2.3.1/bin/scss-lint

最後に linter-scss-lint の Settings の Executable Path に、上記パスの binwrappers に置換したパスを入力します。

/Users/sasaki_yutaka/.rvm/gems/ruby-2.3.1/wrappers/scss-lint

f:id:sskyu:20160726161007p:plain

この状態で .scss ファイルを編集するとリアルタイムに lint 結果が表示されて作業が捗ります。

f:id:sskyu:20160726161520p:plain

同様に、linter-coffeelintlinter-eslint も設定しておくと良いでしょう。

まとめ

この記事では Rails アプリケーションに scss-lint を設定する一例をご紹介しました。

エラーを 0 にして CI で回せることをゴールに設定したため妥協してルールを緩くしました。
ここからは緩くしたルールを厳しくして、リファクタに努めていくフェーズとなります。

Wondershake ではサーバーサイドエンジニアや iOSAndroid ディベロッパーを募集しています。
興味をお持ちの方は是非こちらからご応募下さい!

www.wantedly.com

Locariで使用しているCocoaPodsたち

こんにちは、iOS開発担当の藤井です。

Cocoapods使ってますか? 今回はみんな大好きCocoapodsの中でLocariでも使用しているライブラリを幾つか紹介します。

AFNetworking

https://github.com/AFNetworking/AFNetworking

ネットワーク系のライブラリとしては知らない人はいないくらい有名なライブラリで、LocariでもAPIとの接続で利用しています。 単純にURLリクエストを投げることから複雑なことまで何でもできるので、サーバサイドと繋げるアプリの場合は最初の選択肢に上がってくるのはこのライブラリではないかと思います。

APParallaxHeader

https://github.com/apping/APParallaxHeader パララックス効果のついたテーブルヘッダを作るのに便利なのがこのAPParallaxHeaderです。 Locariでは各記事のカバー写真をパララックス効果を入れて表示しているのでこのライブラリを使用しています。

Fabric & Crashlytics

Twitterに買収されたCrashlyticsがFabricとして提供しているのがこれで、バグレポートやアプリの利用状況などをリアルタイムで送ってくれます。

ionicons

http://ionicons.com/ ioniconsはiOS/Androidアプリ内でよく使いそうなアイコンをカスタムフォントとして利用できるライブラリです。UILabel内で文字としても表示できますし、UIImageView内に画像として表示することもできるので非常に使い勝手が良いです。

MagicalRecord

https://github.com/magicalpanda/MagicalRecord これもかなり有名なライブラリですが、CoreDataを扱う上で非常に便利なO/Rマッパーです。これを利用せずにCoreDataを扱うことはもうあまりないのでは…? というくらい依存度が高いです。

SDWebImage

https://github.com/rs/SDWebImage AFNetwowrkingと同じく画像ダウンロードを行うライブラリとしては有名なこのライブラリも入れています。 Jpeg形式の画像だけでなくWebPも扱えるため、転送量のダイエットにも役立ちます。

youtube-ios-player-helper

https://github.com/youtube/youtube-ios-player-helper 記事内でYouTube動画を再生する為に利用しています。VideoIDをセットするだけでYouTube再生用のViewを生成してくれます。フルスクリーンにならずに再生できるのがさり気なく良いです。

VTAcknowledgementsViewController

https://github.com/vtourraine/VTAcknowledgementsViewController どういったCocoapodsを利用しているのかライセンスとしてまとめてくれる便利なライブラリがこれです。plistで設定してあげると自動的に有効なCocoapodsがリストアップされたViewControllerを生成してライセンスとして表示できます。 アプリに使用しているライブラリのライセンス表示を入れたいけどライブラリを追加・削除する度に更新するのが面倒、という時に活躍してくれます。

Locariでは他にもたくさんのCocoaPodsを利用していますが、主だったものを上げてみました。 他にもこんな便利なCocoaPodsあるよ!というのがあればぜひ教えてください :)

またWondershakeではCocoaPodsに詳しいiOSエンジニアも募集中です。 www.wantedly.com