クラシル開発ブログ

クラシル開発ブログ

【Rails】 ActiveHash gemのクラシルでの事例とハマりポイント

f:id:rnitame:20200814180029p:plain

こんにちは、開発部の高橋です。f:id:jity:20200225114534p:plain

最近弊社のRailsプロジェクトでactive_hashというgemが使われ始めました。

個人的にも結構重宝しているgemでとても便利なのですが、一方で特性を理解せずに使うとハマりやすいgemでもあると思っています。

今回は、ActiveHashのクラシルでの事例と自分の過去の知見に基づくハマりポイントなどを書いていきます。

目次

ActiveHashとは

データをRDBではなくHashやYAMLで定義し、それをActiveRecordライクに利用できるGem。

コード上にデータを持つためmigrationやseedなどの考慮が不要で、テーブルを持つほどでもない・ほとんど変更のないようなちょっとした静的データを保持する際にとても便利です。

詳しい使い方はREADMEを見てほしいですが、基本的には以下のようにActiveHashに用意されているクラスを継承し、データを設定して使います。

class Foo < ActiveHash::Base
  self.data = [
    { id: 1, name: 'a' },
    { id: 2, name: 'b' },
    { id: 3, name: 'c' },
  ]
end

上記のようにdata属性にデータを追加していく方法以外にも、json,yamlなどのファイルにデータを設定してを読み込ませることもできます。

クラシルでの事例

導入経緯

以前もブログにて紹介された「サーバーサイド&SRE改善MTG」での議題として自分が発案し、導入に至りました。

ちなみに、この改善MTGは1月で1周年を迎えたようです 🎉

tech.dely.jp

もともとクラシルのプロジェクトにはactive_hashが使われるようなユースケースが存在しており、すでにレポジトリ内にYAMLなどで定義された静的データが散在してました。

それらがバラバラに管理され、使われ方も統一されていなかったところを一元化したいというところが主な導入意図です。

また、今後何かしらのマスターデータを管理していく際にも便利なので、今のうちに入れておきたいということで入れました。

使われ方

データはyamlで管理し、app/models配下にActiveRecord継承なモデルと一緒に置くというおそらくはスタンダードな使い方で利用してます。

ActiveYamlRecordという親クラスをつくり、各クラスで継承していきます。

# app/models/active_yaml_record.rb
class ActiveYamlRecord < ActiveYaml::Base
  set_root_path Rails.root.join('config', 'masters')
end

# app/models/foo.rb
class Foo < ActiveYamlRecord
end
- id: 1
  name: 'aaa'
- id: 2
  name: 'bbb'
# ...

2020年2月時点ではまだ3モデル程ですが、これから要所要所でガンガン使っていきたいと思っています。

ハマりポイント

ActiveHash導入に関して、自分の過去の経験からハマりやすい(ハマった)ポイントをいくつかご紹介しようと思います。

インスタンス変数がクラスインスタンス変数相当

ActiveRecordでは取得されるごとに生成されるオブジェクトは異なりますが、ActiveHashでは常に同じオブジェクトが返ります。

これはデータが読み込まれる際に各レコードのインスタンスが作成され、クラスインスタンス変数に保持され使い回されるからです。

以下はActiveRecordとの挙動の差です。

class Foo < ActiveHash::Base
  self.data = [
    { id: 1, name: 'a' },
    { id: 2, name: 'b' }
  ]
end

require "active_record"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Schema.define do
  create_table :bars, force: true do |t|
  end
end

class Bar < ActiveRecord::Base
end
Bar.insert_all([{id: 1}, {id: 2}])

b1 = Bar.first
b2 = Bar.first
p b1
#=> #<Bar id: 1>
p b2
#=> #<Bar id: 1>
p b1.equal? b2
#=> false

f1 = Foo.first
f2 = Foo.first
p f1
#=> #<Foo:0x00007ff31791e738 @attributes={:id=>1, :name=>"a"}>
p f2
#=> #<Foo:0x00007ff31791e738 @attributes={:id=>1, :name=>"a"}>
p f1.equal? f2
#=> true

このような挙動になるため、ActiveRecordと同じ気分でインスタンスの状態を変更するとハマるので注意が必要です。

class Foo < ActiveHash::Base
  self.data = [
    {id: 1, name: 'a'},
    {id: 2, name: 'b'},
  ]

  attr_accessor :foo
end

f1 = Foo.first
f1.foo = 'bar'
p f1.foo
#=> "bar"

f2 = Foo.first
p f2.foo
#=> "bar"
# nilではなくf1で代入した値が返る

データがロードされるタイミング(特にActiveYaml, ActiveJsonの場合)

これはActiveYamlやActiveJsonなど、データをファイルで持ってる場合に特に気をつけたいことです。

これらのクラスのデータロードのデフォルトの挙動は、取得メソッドが実行されたタイミングになります。

具体的には以下のメソッドが実行された際にファイルのパースが実行され各クラスにデータが格納されます。

  • find
  • find_by_id
  • all
  • where
  • method_missing

github.com

class Foo < ActiveYaml::Base
  set_root_path File.expand_path(__dir__, './')
end
# この時点ではまだYAMLは未ロード

Foo.find(params[:id]) # ここで初めてYAMLが読み込まれる

小さいデータであれば問題はないようにも思えますが、大きなデータの場合は初回リクエストだけロードに時間がかかるようになってしまいます。

また、スレッドセーフな作りになってるわけではなさそうなので、複数スレッドで実行される際にも注意が必要です。

以下のように、意図しない挙動になってしまう可能性があります。

class Foo < ActiveYaml::Base
  set_root_path File.expand_path(__dir__, './')
end

t1 = Thread.new do
  p Foo.first
  p 't1 done'
end

t2 = Thread.new do
  p Foo.first
  p 't2 done'
end

t1.join
t2.join
$ ruby sample.rb
nil
"t2 done"
#<Foo:0x00007fe224c622e0 @attributes={:id=>1, :name=>"name1"}>
"t1 done"

これはおそらく以下のような状況になってるものと思われます。

  • t1
    • ActiveFile::Base.firstが呼び出される
    • データ読み込みフラグ(data_loaded)のチェック
    • .reloadが呼び出される
    • data_loadedフラグがtrueになる
    • YAMLのロード処理が走る
  • t2
    • ActiveFile::Base.firstが呼び出される
    • データ読み込みフラグ(data_loaded)のチェック
    • データ読み込み済み(data_loaded=true)と判定される
    • ActiveHash::Base.firstが呼び出される
    • t1のロードが終わっておらずデータが空なので[].firstが処理として実行される
    • nilが返る
  • t1
    • YAMLのロード完了
    • ActiveHash::Base.firstが呼び出される
    • レコードが返る

アプリケーションサーバーなどでマルチスレッドな環境を利用している場合は、意図しない挙動が引き起こされやすい状況と言えそうです。

対応策

この対応策として思いつくものとしては、クラスロード時にデータを読み込んでしまうことです。

class Foo < ActiveYaml::Base
  self.reload
end

上記のようにクラス定義で.reloadを呼び出せばクラスが読み込まれる起動時などにデータを読み込ませることができるため、メソッドの初回呼び出し時でもロードが行われません。

あるいは、config/initializers配下で呼び出す方法もあるかと思います。

#  https://github.com/zilkey/active_hash#defining-data の応用
# config/initializers/data.rb
Rails.application.config.to_prepare do
  Country.reload
end

ただしどちらも起動が遅くなるというデメリットがあるため、各々のアプリケーションに適用できるかどうかは要確認です。

いずれにせよ、利用前にある程度意識しておく必要はあるかと思います。

最後に

delyではRailsエンジニアを絶賛大募集中です。

  • 大量のトラフィックをさばきたい
  • 食の課題を解決したい
  • ユーザーファーストな開発がしたい

といったことに少しでも興味があるかたは、是非お声がけください!

www.wantedly.com

Rails Girls Tokyo 13thにスポンサー協賛&コーチ協力をしました!

f:id:mochizuki_pg:20200226140555j:plain

こんにちは! サーバーサイドエンジニアの望月です!

先日開催された「Rails Girls Tokyo 13th」に、
delyはスポンサーとして協賛してきました!

また今回は、私とサーバーサイドエンジニアの安尾が
コーチとして参加者のサポートもさせていただきました。

今日はその様子をかんたんにご紹介したいと思います。

Rails Girlsとは?

f:id:mochizuki_pg:20200125090537p:plain

railsgirls.com

Rails Girlsとはプログラミングに興味のある女性が
コーチである現役のエンジニアのサポートのもと、
全2日間でWebアプリケーションを1から作ってみるイベントです。

13回目の開催となる今回はプログラミング初挑戦の方や、
デザイナーの方、会社のプロダクトがRailsを使用している人事の方など、
合計で25人のガールズが参加してくださいました。


Rails Girlsのスポンサーになりました&LTをしました!

delyでは運営しているレシピ動画サービス「クラシル」の
web・アプリでサーバーサイドとして
Ruby、そしてフレームワークとしてRailsを使用しています。

www.kurashiru.com

RailsはRubyのフレームワークであり、
Rubyの開発者のMatz(まつもとゆきひろ) さんいわく
enjoy programming がコンセプトになっているため
可読性が高く、わかりやすいです。

またRailsは DRYやCoCなどRails Wayや、豊富なgemなど
高速に開発が進めることができる、という特徴から
delyでもクラシルの開発にRailsを採択しています。


今回クラシルを運営しているdelyとしても
Ruby、Railsコミュニティに対してなにか貢献したいと思い、
GitHubさんやSansanさん、SmartHRさんなどとともに
今回スポンサーとして協賛させていただきました。



当日はスポンサー枠でサーバーサイドエンジニア 安尾による
会社紹介LTもさせていただき、
“delyの魅力を 「4P」でお伝えします!”というテーマのもと、
delyやクラシルについてご紹介しました。

企業の魅力因子とも言われる「4P」とは

・Philosophy(理念・目的)
・Profession(仕事・事業)
・People(人材・風土)
・Privilege(特権・待遇)

のこと。

delyがこれら4Pに対して、
どのような取り組みをしているかをお話させていただきました。


参加者のみなさんに、
「あなたにとって一番大切なPはなんですか?」という質問をして、
挙手をしてもらったところ、それぞれのPにわかれる結果に。

若干ではありましたが、Philosophy(理念・目的) が多かった印象を受けました。

f:id:mochizuki_pg:20200218114214j:plain f:id:mochizuki_pg:20200216135008j:plain

また、「クラシルを知っている方〜」という質問にも多くの手が挙がりました!🙌


LT後にもたくさんの方から、
「4Pって始めて知りました!」「LT良かったです!」と、
声をかけてもらって嬉しかったです!!

クラシルでは、アプリ、WebともにRailsで開発をおこなっています

(笑いもあり、みなさん積極的に参加してくれて感謝です🙂)

コーチとしても参加しました


今回はスポンサーとしての協賛だけでなく、
プログラミングに興味のある参加者の方のサポート役として
サーバーサイドエンジニアの安尾と、コーチもしてきました。

f:id:mochizuki_pg:20200127095909p:plain

プログラミング自体が初挑戦の方もいたので、
数時間で多くの知識を学ぶのは、なかなかハードではありましたが
皆さん真剣に取り組んでいました。

コーチとしてもいかにわかりやすく伝えられるかを考え
質問などにも丁寧に納得のいくまで回答するように心がけました。

当日の様子

ザッハトルテチーム


マカロンチーム

無事デプロイができました〜〜🎉🎉


参加者の方のなかにはこんな嬉しいツイートをしてくださっている方たちも。

今回参加して/コーチをしての感想


安尾:
私が担当させていただいたガールズさんで、
普段はQA担当としてエンジニアと一緒に業務をしている方からは
「普段エンジニアと話していて理解できなかったことが今日一日で色々と分かるようになって嬉しかった!」
というフィードバックを頂くことができました。
プログラミングを学びたいという気持ちに
少し応えられたかなととても嬉しかったです。
今後もまたコーチとして参加できればと思っています!

望月 :
マカロンチームのコーチをしましたが、
もう既にプログラミングを学習している方や
普段はデザイナーとしてフロントエンドのコーディングをしている方だったので、
皆さんの理解がはやく、特に問題が起きることもなくデプロイすることができました。
プログラミングは楽しいので、これからも続けていってくれたらなと思います。

最後に

今回私たち2人ともコーチとして初めての参加でしたが、
プログラミング初心者の方にどうしたらわかりやすく伝えることができるか、
どうやったらプログラミングを楽しんでもらえるかを
改めて考える良いきっかけになりました!


これからもdelyではRuby、Railsコミュニティへの貢献をしていき
Railsを活用してより良いプロダクトを世の中に届けていきたいと思います。

"80億人に1日3回の幸せを届ける" というミッションのもと
一緒に挑戦してくれるRailsエンジニアを募集しています!

www.wantedly.com

チームのコミュニケーションをより円滑にし、スピードを上げていくための取り組み

こんにちは、dely の Android チームで施策をやりながらアプリ改善に取り組んでいる tummy です。 以下記事を書いてからもう 2 ヶ月が経過し、Android チームも 1 人増えて 4 人になりました。この 3 ヶ月でメンバーの数が倍になっています(すごい)

tech.dely.jp

この 3 ヶ月間主に阿吽の呼吸でまかなえていたことを掘り起こして文章化し、チームの共通認識を作るところに注力していました。今回はその取り組みについて紹介できればと思います。

リリースマネージャーのような役割になってみる

Android チームは 1 人 1 つ何かしらの施策を担当しており、同時並行で進んでいます。2〜3 人の時期は、bot のレオくんが水曜日になるとそろそろリリースしない?とお知らせしてくれるので、それをみたときにリリースするかどうか決めていました。

f:id:rnitame:20200225085543p:plain
レオくんがお知らせしてくれている様子

しかし 3 人中 2 人が大きめの施策を担当しているのもあり、なかなかリリースしようという雰囲気になることが少なかったです。そして、4 人目がジョインした今月、細かい施策が爆速で進むようになった結果、1 週間経った時点でマージされているプルリクが 10 を超えるようになりました。

さすがにこれはコンスタントにリリースしていかないとやばいと思い、リリースマネージャーのようなことをするようになりました。とはいってもそこまで形式張ったことはやっておらず、主に以下のようなことをしています。

  • リリースサイクルの策定(次に詳細を書きます)
  • リリース作業、及びその効率化

以下の記事で書かれているように、弊社の Android CI は bot が大変活躍してくれているので、より多くの過程を bot にまかせられるように実装 & 調整中です。

tech.dely.jp

リリースサイクルの策定

やりました。経緯は上記に書いたとおりです。プロダクトレビューという文化が弊社にはあるため、そのレビュー結果への対応期間も考慮しつつも、基本的には水曜日にコードフリーズ & デバッグ、何もなければ木曜日リリースというフローを踏んでいます。

f:id:rnitame:20200225091143p:plain

リリースノートの自動化など、このサイクル内でもまだ自動化できそうな箇所があるので、引き続き模索していきます。

設計について議論したりする場所が爆誕

f:id:rnitame:20200225091435p:plain
クラシル Android の最初のコミットログ

クラシル Android は 4 年もののアプリで、設計も複数パターンあったりしてとても複雑になっています。メンバーが 3 人になり、こういった箇所にもだんだん手を入れられるようになってきたことと、過去の事情によって実装されている箇所などを質問する場として Android エンジニア MTG が生まれました。

4 人になった現在は設計をこれからどうしていくか、コードスタイルについてどれを採用していくかなど、古くからあった懸念への対応方針について議論することが多くなり、改善方面にも力を入れられているのでとても活発になっています。(次回で 6 回目まで来ました 🙆)

f:id:rnitame:20200225092506p:plain

議事録や仕様書の共同編集化

プロダクトレビュー等を通してガンガン仕様が変わる弊社ですが、仕様書が過去のまま更新されず、最新状態がわからないという問題がありました。また、それに伴い仕様の認識のズレが起きてしまっていました。 そこで、Qiita に共同編集にしたほうがいいものとしなくてもいいものを画像つきで記事にしてみました。

f:id:rnitame:20200225105542p:plain

この記事がきっかけになったのか、積極的に共同編集にしてくれる方が増えてきててとても嬉しいです。 まだ問題は残っていますが、解決の一歩になったのではないかと思っています。

プロダクトレビューについての内容の明確化

プロダクトレビューは CXO の坪田さん発信で始まったものですが、なぜ?何をみてるの?という観点が明確ではありませんでした。そのせいか、せっかくのレビューの機会でぎくしゃくした雰囲気になることがありました。 そこで、自分が集められる情報を Qiita にまとめて坪田さんに共有、ヒアリングすることで足りない箇所をアップデートしました。坪田さんにとてもわかりやすい資料も作成いただいて、全体に共有されました。これからどんどんこの考えが浸透していくといいなと思いますし、自分も意識したいなと思います。

まとめ

ざーっと今までやってきた取り組みをご紹介しました。まだまだやれることはたくさんあるので、引き続きやっていきます。 また新しい取り組みを始めた際にはブログでお知らせできればと思います!

dely では様々なポジションのエンジニアを積極採用中です!興味がある方はぜひご連絡ください!

ユーザーお問い合わせの技術的サポートについて

はじめまして。開発部の sakura818uuu です。
CS(カスタマーサクセス)チームのサポートエンジニアを始めて2ヶ月が
経過しました。

今回は、ユーザーお問い合わせの技術的サポートについて
具体的にどんなことをやっているかをご紹介しようかと思います。

はじめに

クラシルでは、ユーザーさんが困った時にお問いあわせをするページがあります。
お問い合わせの内容は課金やメルマガ、不具合の報告など様々です。

f:id:sakura818uuu:20200217093631j:plain


お問い合わせがあるとCSチームがユーザーさんとのやり取りを行います。
技術的サポートが必要な場合は、開発部のCS技術的サポート役にご相談
いただくフローになっています。

去年の12月から私が技術的なサポート役を担当しています。

f:id:sakura818uuu:20200217090238p:plain

どんなお問い合わせが多いのか?

課金やメルマガ、不具合のお問い合わせが多いです。

※技術的サポートをしたお問い合わせに限るため、お問い合わせ全体のデータではありません。

お問い合わせの対応件数などを可視化して社内に共有をしています。

f:id:sakura818uuu:20200218080815j:plain

月によってお問い合わせ内容の傾向は違います。
新機能追加やマーケティング施策によってお問い合わせ内容の傾向は変化するので、 日々のキャッチアップが非常に重要なことを身にしみて感じています。

どうやってサポートしているのか

サポート方法はケースバイケースですが、主に3種類の方法があります。

1.ツール

お問い合わせの内容に合わせて様々なツールを使います。
ツールでしか得られない情報や設定できない情報があるためです。

調査/設定した結果をもとにCSチームにご連絡します。

メルマガツール・課金管理ツールなど扱うツールの数はたくさんあります。
この2ヶ月でツールの使い方は全て社内にドキュメント化しました。

f:id:sakura818uuu:20200217113251p:plain:w270
Qiita:Teamに数十個の記事があります

ドキュメント化したことで確認する時間が減り対応時間が削減されました。

2.データ

お問い合わせを調査する時に、ツールを使う以外に
SQLでデータを出して調査することも多いです。

データを出して調査した結果をもとにCSチームにご連絡します。

主にredashでクエリを書いています。
CSの調査でよく使うクエリはお気に入り登録して、すぐ使えるようにしています。

f:id:sakura818uuu:20200217140423p:plain

参考:redashのクエリお気に入り登録について

tech.dely.jp

3.開発部内で相談

アプリの不具合やサーバーサイドが絡んできそうなお問い合わせには、
私だけで解決できないので開発部内のメンバーと相談します。

開発部とCSチームのハブになって動きます。
ハブの役割は以下のようなことをしています。

f:id:sakura818uuu:20200217132139j:plain

<開発部へ伝えるとき>
・エンジニア側が調査しやすい情報を事前に揃える
・いつから何件発生しているかなど対応の温度感を伝える

<CSチームへ伝えるとき>
・技術的な用語を使わずに原因を説明
・調査に時間がかかりそうな場合の調整や対応検討

開発部のメンバーとはなるべく密に連絡を取り合うようにしています。
いつも迅速に対応していただきすごく助かっています。

さいごに

CS(カスタマーサクセス)チームのサポートエンジニアとして
ユーザーお問い合わせにどのように対応しているか
をご紹介しました。

多種多様なお問い合わせが来るため調査が難しいこともありますが、
CSチームや開発部に助けてもらっています。

「迅速に、丁寧に」ユーザーさんのお問い合わせに答えられるよう
これからもサポートしていけたらと思います。


delyの開発チームについて詳しく知りたい方はこちらをどうぞ

Zendeskからslackへの通知方法

はじめまして。sakura818uuuです。
Zendeskのチケットをslackに通知する方法をご紹介します。

はじめに

現在、私はCS(カスタマーサクセス)チームの技術的なサポートを行っています。

note.com

delyのCSチームでは、Zendeskを去年から使い始めました。
Zendeskのチケットが届いたり更新されたりすると、slackに通知が飛ぶようにしておりとても便利です。

このブログでは、Zendeskのチケットをslackに通知する方法をご紹介します。

手順方法

Incoming Webhookの設定、Zendesk拡張機能の設定、Zendeskトリガの設定を順に行っていきます。

Incoming Webhookの設定

  1. このページでIncoming Webhookと検索・選択します

f:id:sakura818uuu:20200207172532p:plain


2. 「Slackに追加」ボタンを押します

f:id:sakura818uuu:20200207154922p:plain


3. Zendeskの通知を飛ばしたいslackのチャンネルを検索・指定します f:id:sakura818uuu:20200207155032p:plain


4. チャンネルの指定が完了したら「Incoming Webhook インテグレーションの追加」を押します f:id:sakura818uuu:20200207161759p:plain


5.インテグレーションの設定 にある Webhook URL をコピーします。 このコピーしたURLは次のZendesk拡張機能の設定で使用します。

f:id:sakura818uuu:20200207162030p:plain

Zendesk拡張機能の設定

  1. Zendeskにログインします
  2. ホーム画面から歯車マークを押し設定ページに飛びます

f:id:sakura818uuu:20200207163145p:plain:w50


3. 設定の拡張機能を選択します

f:id:sakura818uuu:20200207163621p:plain:w200


4. ターゲットを追加を選択します

f:id:sakura818uuu:20200207163707p:plain


5. HTTPターゲットを選択します f:id:sakura818uuu:20200207164215p:plain


6. HTTPターゲットの所定の欄を埋めていきます。

↓デフォルト f:id:sakura818uuu:20200207164405p:plain

↓埋めたもの f:id:sakura818uuu:20200207164458p:plain

・タイトルはご自由に
・URLはIncoming Webhookの設定の5の手順で得たURLを貼り付け
・方法はGETからPOSTに変更
・コンテンツタイプはJSON (コンテンツタイプはデフォルトでは表示されていませんが、方法をPOSTにすると表示されます)
・基本認証は今回はチェックなし


7. 送信ボタンの横にある選択肢をターゲットのテストからターゲットの作成に変更します f:id:sakura818uuu:20200207165255p:plain


8. 送信ボタンを押します f:id:sakura818uuu:20200207165337p:plain


9. ターゲットが作成されたら完了です

f:id:sakura818uuu:20200207165506p:plain

Zendeskトリガの設定

  1. Zendeskにログインします


2. ホーム画面から歯車マークを押し設定ページに飛びます

f:id:sakura818uuu:20200207163145p:plain:w50


3. ビジネスルールのトリガを選択します

f:id:sakura818uuu:20200207165748p:plain


4. トリガを追加 を選択します

f:id:sakura818uuu:20200207165832p:plain


5. トリガ名と説明を書きます

f:id:sakura818uuu:20200207165942p:plain


6. 条件を設定します。ここの条件は使いやすいよう適宜変更してください。

今回の条件:
「チケットが作成され、ステータスが解決済みではなく、チケットにパブリックコメントがあるとき」

f:id:sakura818uuu:20200207170114p:plain


7. アクションを設定します。

まず、「ターゲットに通知」を選択します。
次に、「ターゲットに通知」の横枠に Zendeskの拡張機能の設定の9 で設定したターゲット名前が出てくるので選択します。
ここでは横枠に「テストです。」を選択しました。

f:id:sakura818uuu:20200207170651p:plain

コピペしやすい用

{
   "attachments":[
      {
         "fallback":"新しいお問い合わせがありました",
         "pretext":"新しいお問い合わせがありました",
         "color":"#D00000",
         "fields":[
            {
               "title":"件名: {{ticket.title}}",
               "value":"URL: {{ticket.url}}"
            }
         ]
      }
   ]
} 


JSONボディももちろんカスタマイズ可能です

参考: Slack API attachmentsチートシート - Qiita


8. 作成ボタンを押します

f:id:sakura818uuu:20200207171145p:plain


9.トリガが作成されていれば完了です

f:id:sakura818uuu:20200207171647p:plain

完成したらどうなるか

Incoming Webhookの設定、Zendesk拡張機能の設定、Zendeskトリガの設定が完了すると Zendeskからslackに通知が届くようになります🎉

f:id:sakura818uuu:20200207172006p:plain:w300

「SRE NEXT 2020」にdelyが協賛&登壇しました!

f:id:gomesuit:20200204233039p:plain

こんにちは。delyのSREの井上です。

delyは先日開催されたSRE NEXT 2020にGOLDスポンサーとして協賛をさせていただきました!当日はセッション枠を頂き、「delyにおける安定性とアジリティ両立に向けたアプローチ」をテーマに発表もさせていただきました。

セッションでは、

  • 前半:SRE本に則った理論の話
    • SREはプロダクト開発の速度を安全に高めるために存在しているということ
    • プロダクト開発の速度を安全に高めるためには単純さを追求することが重要であること
  • 後半:前半の理論に則ったdelyでの実践の話

をしました。スライドは公開済みですが、それだけだと伝わりにくい内容も含めてブログにも投稿させていただきます。

f:id:gomesuit:20200205143342j:plain

f:id:gomesuit:20200205143359j:plain 当日は多くの方が参加されていました!

SRE NEXTに参加してみて

SRE Loungeの勉強会は#5以降の会は全て参加させて頂いているのですが、いつも有意義な情報が得られて登壇者や運営の方には感謝しかないなと思っていました。なので、SRE NEXTでスポンサーという形でコミュニティに貢献できたことは良かったなと感じています。登壇の機会を頂けたことも感謝しかなく、今後も引き続きよろしくお願いしますという感じです。

個人的にすごく印象に残ったのはSREの今後というトピックでした。時代の変化でアジャイル開発やスクラム開発が当たり前の存在になったように、おそらくSLOやエラーバジェットも今後何かのフレームワークに落とし込まれて開発文化に取り入れられていくのだろうと思いました。そうなるとSREの存在意義はほとんどなくなるので、どういった形に役割が変化していくのかなというところを考えるのも面白そうだなと思いました。

目次

SREの存在意義

SREは「信頼性を高めるため」ではなく、「プロダクト開発の速度を安全に高める」ために存在しているということを出来る限り分かりやすく伝えるべく、SRE本に記載されている内容を元に順序立てて説明をしていきました。

SREが成し遂げようとしていることは結局SREだけでは達成できず、必ずプロダクト開発チームやマネジメント層との連携が必要になります。他組織と連携するためにもSREが何をしようとしているのかを誰もが理解できるように、可能な限り噛み砕いてスライドに落とし込みました。

旧来のサービス運用と組織分離

AWSやGCPが存在しない時代における「システム管理者」の業務は、既存ソフトウェアの活用だったので、サービスの運用業務はソフトウェアの開発業務とは別のスキルセットが必要とされました。

サービスが成長してくると、必然的に運用業務に人手が必要になるので人員調達の観点からほとんどの企業で開発と運用の組織が分離されました。

この組織分離には人員調達以外の点で大きなデメリットが存在します。

組織分離によって発生するコストとSRE

組織分離によるデメリットは直接的なコストと間接的なコストに分けられます。

  • 直接的なコスト
    • 手作業の運用業務による人件費の増加
  • 間接的なコスト
    • 目標の違いが引き起こす対立構造による開発スピードと安定性の低下
      • 開発組織の「新しい機能を早くリリースする」という目標
      • 運用組織の「サービスに問題が起きないようにしたい」という目標

これらのコストに対するGoogleのとったアプローチがSREになります。

コストに対するSREのプラクティス

f:id:gomesuit:20200203014326p:plain

SRE本に記載のあるいくつかのプラクティスをコスト別に分類してみました。

直接的なコストに対するアプローチは主に、「運用作業をどのように自動化するのか」と「自動化に使える時間をどうやって維持するか」の大きく2種類に分かれます。

間接的なコストに対するアプローチは主に「組織間の対立構造をどのように解消するか(発生させないか)」に焦点を当てたものになり、SLOやエラーバジェットはこちらに分類されると考えています。

SRE NEXTでもどちらの内容をテーマにするのか発表ごとに分かれていて、どちらに課題感を大きく感じているのかを考察しつつ聞くのもまた面白かったです。delyの発表では間接的なコストの方に対するアプローチについてお話しました。

対立構造が引き起こすプロダクト開発速度の低下

f:id:gomesuit:20200203020535p:plain

SRE本の中で「間接的なコスト」として語られている内容を図に落とし込みました。開発と運用の目標の違いが最終的にプロダクト開発速度を低下させる構造になっています。

重要なポイントとしては、開発/運用の組織体制が開発/SREという組織体制になったからといって、ただそれだけでこの対立構造が解消するわけではないという点です。

開発速度/安定性のバランスのコントロール

f:id:gomesuit:20200204020248p:plain

プロダクト開発速度を最大化させるには、開発速度/安定性のバランスをコントロールする必要があります。

ある項目において開発速度と安定性どちらを取るのか決めなければいけないタイミングが多々あると思いますが、客観的なデータがない限り交渉力のある人であったり立場のある人の一声で最後は決まってしまうと思います。

その場合、誰かの感覚がバランスを取っているということになると思うのですが、その「誰か」はどこかの組織に属しているはずなので結局、対立構造は解消しないということになってしまいます。

エラーバジェット

「誰かの感覚」に終止符を打つSREのプラクティスがエラーバジェットです。

f:id:gomesuit:20200204021555p:plain

予算がなくなった時点でリリースできなくなるという超強力なポリシー・・・!

f:id:gomesuit:20200204021611p:plain

機能のリリース速度を最大化するためにエラーバジェットの導入をSREの目標としましょうという内容がSRE本には記載されています。

f:id:gomesuit:20200203020735p:plain

エラーバジェットによって目標を統一することで、開発速度と安定性をコントロールしプロダクト開発速度の最大化を図ることが可能になります。

SREの存在意義の再確認

f:id:gomesuit:20200204031113p:plain

エラーバジェットの仕組みからも読み取れる通り、SREはSLOやエラーバジェット等のプラクティスを駆使して組織の対立構造を解消し、プロダクト開発の速度を安全に高めるために存在しているということが言えると思います。

エラーバジェットとは別のアプローチ

とはいってもエラーバジェット導入の難易度って時間がかかりますよね。なので、SRE本に載ってるプロダクト開発の速度を安全に高めるための別のアプローチも同時に紹介しました。

エラーバジェット導入の難易度

f:id:gomesuit:20200203034808p:plain

エラーバジェット導入の難易度はとても高いです。

「その期間のエラーバジェットを消費しきったら残りの期間リリースができなくなる」というルールは、運用しているサービスのビジネスモデルによってはかなり厳しいポリシーだと思います。

もちろん、SREの文化を浸透させ最終的にはエラーバジェットの導入を目指すべきだとは思いますが、導入しようと思って数日でできるような手軽なアプローチではないことは間違いないです。

SRE本においてはエラーバジェット以外にもプロダクト開発の速度を安全に高めるためにSREがすべきことについて触れており、発表ではその内容について紹介しました。

それは想定外の複雑さの削減単純さの追求です。

想定外の複雑さとSRE

f:id:gomesuit:20200204032636p:plain

SRE本においては開発速度と安定性がどちらも低下する要因として想定外の複雑さを挙げています。

具体例としては、ソフトウェアの領域においては密結合なソースコード、インフラの領域においては手作業で構築されたサーバなどが挙げられます。

想定外の複雑さはレイヤーに関係なく発生しますが、どこに存在していたとしても開発速度と安定性のどちらも低下させる要因になってしまいます。

f:id:gomesuit:20200204033114p:plain

SRE本には想定外の複雑さに対してSREがとるべき行動が記載されています。

  • 受け持っているシステムに想定外の複雑さが生じていたら差し戻す。
  • 関わっているシステムや、運用を受け持つことになるシステムから複雑さを取り除く努力を継続的に行う。

単純さの追求による開発速度と安定性の両方の向上

f:id:gomesuit:20200204033058p:plain

ソフトウェアやインフラなどの領域に関わらず、想定外の複雑さを継続的に削減していくことと、想定外の複雑さを新たに作り込まないことが、開発速度と安定性を両方高めていくためには必要です。

delyでの実践

後半はdelyにおける実践の話をしました。

正直なところ、他社の参考にできそうな奇抜な施策が出来ている状況ではないです。そもそも当たり前なことがまだちゃんと出来ていない状態なので、ひとつひとつの課題解消を愚直に進めつつ基盤を整えているフェーズです。

そういったフェーズの会社が他にも存在すると思ったので、やっていることは割と普通なのですが、dely自体のことも知ってもらえる良い機会だと思いいくつか紹介させて頂きました。

規模とフェーズ

f:id:gomesuit:20200203030300j:plain

サービスや組織のフェーズをまず知ってほしいと思ったので、サービスの規模とメンバーの増加傾向がわかるようにグラフを見て頂きました。

おかげさまでサービスは年々成長を続けていて、開発のメンバー数も増加傾向にあるのですが、注目してほしいのは2016年から2018年までの2年間、サーバサイドがほぼ1人での開発だったというところです。

この頃の状況は下記の2つの記事から読み取ることが可能です。

note.com

www.fastgrow.jp

2019年前半までとにかく機能リリース優先でやってきたこともあり、最近になってサービスの成長に伴って品質やセキュリティなどの点でいろいろな問題が発生し始めました。

課題

f:id:gomesuit:20200203025647p:plain

クラシルは開発開始から4年ほどが経っています。当然のように様々な課題を抱えています。

現状の課題が多いからといって、今までの選択が決して悪かったというわけではないですが、フェーズが変われば課題も変わるということは事実なので、話し合うべきなのは 「これからどうしていくか」というところだと思っています。

具体的なアプローチ

f:id:gomesuit:20200203025618p:plain

delyでは直近1年をかけて想定外の複雑さを減らし、今以上に増やさないための文化づくりをしてきました。

下記の3つの視点でアプローチを行いました。

  • 何が複雑なのかを認識し共有することにより可視化する
  • 複雑なものを減らす計画
  • 複雑なものを新たにつくらない仕組みづくり

想定外の複雑さを減らすアプローチ

改善MTG

f:id:gomesuit:20200203035120p:plain

f:id:gomesuit:20200205000650p:plain

複雑さの箇所を可視化するために行っているのが改善MTGです。想定外の複雑さを一番把握しているのは現場のメンバーですが、改善MTGを実施することでその感覚を言語化し、メンバー間で共有することを目的にしています。

想定外の複雑さも誰かの感覚の中にある限り、解消することは理論上不可能です。しかしMTGを行いメンバー間で議論を行うことで、感覚の先の根本的な課題が明確になっていき、どういった対応が考えられるのかや解消によって得られる効果などが言語化されます。PdM等のタスクの優先順位付けに決定権を持つ人が、機能開発タスクより改善タスクの優先度を上げるという意思決定をできるように可視化しておくことが想定外の複雑さを解消するためには必須であると考えています。

改善MTGの詳細については既に記事があるので興味があればこちらを読んでみてください。

tech.dely.jp

課題洗い出し会

f:id:gomesuit:20200205001012p:plain

f:id:gomesuit:20200205001741p:plain

改善MTGも運用開始直後においては課題の提案が特定のメンバーに偏るという課題がありました。その課題に対して行ったのがこの課題洗い出し会になります。

課題が潜んでいそうな技術分野をリストアップし、メンバー間で回答が見えないようにそれぞれの分野に対する課題感を回答してもらいました。その回答をマージして課題感がメンバー間でずれている箇所に対して議論をします。議論した内容をもとに課題を登録してもらうことで、今までなかった観点の課題が提案されるようになりました。

課題の提案もある程度慣れが必要な部分だとは思うので、不得意なメンバーでも提案しやすくなるような仕組みや、新しいメンバーが遠慮してしまわないような工夫が重要だと考えています。

リファクタリング計画

f:id:gomesuit:20200205004439p:plain

改善MTGはあくまで可視化までが目的になっているので、解消していく工程については別途、別の手段で進める必要があります。誰か1人が進めるのではなく分担して解消していく必要があるので、やみくもに進めるのではなく計画をたてるようにしています。

スプレッドシートに今抱えている課題を一覧化して、重要度と緊急度の観点から優先順位を議論して決めます。優先順位に伴って、誰がどの課題を解消するのか担当を埋めていきます。あとは担当者が愚直に解消していくという感じで進めています。

詳細については既に記事があるので興味があればこちらを読んでみてください。

tech.dely.jp

想定外の複雑さを増やさないアプローチ

設計レビュー

f:id:gomesuit:20200205005913p:plain

増やさないためのアプローチの一つとしては設計レビューを紹介しました。

想定外の複雑さを解消していっても、別のところで随時新しく生まれていたら削減している意味がないです。

サーバサイドエンジニアの数が増えてきたタイミングで、コードを書き始める前に設計完了時点でレビューをするように開発フローに組み込みましたが、SREもSLOの維持に責任を持っているので、アーキテクチャの観点など想定外の複雑さが発生していないかレビューできるようにSREも参加を必須にしています。

内容によってはかなり時間をかけて議論を行っていて、コードを書く前から全員で徹底的に議論を行うような文化が出来ています。

このあたりの内容はコアすぎてあまり書けないのですが、何かの振り返りのタイミングで記事を書いて共有できればと考えています。

意識

目的と手段の可視化

f:id:gomesuit:20200205005955p:plain

f:id:gomesuit:20200205013542p:plain

いろいろなアプローチを考えつつ複雑さを解消しているのですが、複数人で分担していくと、ついついリファクタリングすること自体に目がいってしまいがちで、本来の目的を見失うことが少なからず発生してしまいます。

リファクタリングすること自体が目的化してしまうと、つい必要のないところまで手を伸ばしてしまうと思うのですが、それをやってしまうと今やらなくてよいものまで実施してしまうことになるので、今までのアプローチの効果が薄れてしまいます。

なので目的と手段を可視化することで、今やっているタスクが何の目的の手段にあたるのかということを常に意識できるようにしています。

例えば、リファクタリングや開発ガイドラインの見直しなどはタスクに分解すると、不足しているテストの作成や開発フローの見直しなどになりますが、これらのタスク自体も手段であって目的のために行っているという状態になっているはずです。意識しなければいけないのは目的の方であり「開発速度と安定性の両方の向上」や更にその上の事業の成長になります。

さいごに

偉そうなことべらべら書いてる割にdelyのSREは実は全然始まってすらいません。少しづつ始めている内容は下記の記事にかいてあるので是非読んで頂きたいです。

tech.dely.jp

もちろんSREを絶賛募集しています!クラシルの開発スピードを落とさず、信頼性も担保するという難易度の高い課題に挑戦したい方はぜひ声をかけてください!

www.wantedly.com

delyの開発チームについて詳しく知りたい方はこちらもあわせてどうぞ

情報共有不足を打破するために試した7つのこと

はじめまして。

dely, Inc.でクラシルの開発に携わっている @sakura といいます。
本記事では、分析データを社内に情報共有するまで私がどんなことしたかを
赤裸々に紹介します。

この記事はデータ活用 Advent Calendar 2019の21日目の記事です。

はじめに

「こんなにも貴重なデータがあるのに全然活用できていない…てか誰も見ていない… 」 この状況を打破すべく一歩一歩やっていったことを共有します💪

泥臭くやったこと

スプレッドシートにしてハードルを下げる

f:id:sakura818uuu:20191217180009p:plain:w400
まずは、データをスプレッドシートにまとめました。

なぜかというと、そのデータがredashでしか閲覧できなかったからです。
エンジニア以外にとってはredashは心理的負荷が高く、スプレッドシートのほうが普段から使い慣れているので扱いやすいです。

弊社ではG Suiteを使用しているので、
スプレッドシートにすることでデータを見るハードルがぐっと下がりました。

データを整理して見やすく、負荷を少なく

f:id:sakura818uuu:20191217195835p:plain:w400

データの性質そのものではなくて、データを閲覧してほしい人を軸にして数千件のデータをカテゴリ分けしました。
上の画像は実際のスプレッドシートです。タブでカテゴリごとに分かれています。

何千件もあるデータを見るのは脳の負荷が高く疲れてしまいます。
従って、事前にカテゴリ分けをしてこの人はここだけ見ればOKというようにしました。

社内の複数人にメンションをつけて共有

f:id:sakura818uuu:20191217183124p:plain:w400

スプレッドシートが完成したら、データを見てほしい人にメンションをつけて共有しました。

特定のチャンネルで特定の人に「こういうデータがあって、ここの部分を利用できると思うんですがどうでしょうか」という風に、 チャンネル / メンションをつける人ごとにメッセージを変え、そのデータの効果が最大化するように努めました。
やってることはパーソナライズに近いかもしれないです。

オフラインで共有してアドバイスをもらう

f:id:sakura818uuu:20191217183352j:plain:w350

オンラインで伝えることは効率がよいですが、一番物理的距離が近く、必ず伝わるのはオフラインだと思い 2つのMTGで「貴重で役に立つデータがここにあるのでぜひ見てください」と共有しました。

その場で見てくださる方もたくさんいて、アドバイスを頂くこともできました。(このデータ役に立ちそう、といわれた時はうれしかったです)

Qiitaにも残して検索しやすく

f:id:sakura818uuu:20191217184230p:plain:w450

全社員が見れる社内の共有ドキュメントツールのQiitaを使い、軽くドキュメントを残しておきました。
slack内に残すと「あれ、あの情報どこいったっけ」となりがちなので、Qiitaにもまとめました。

ドキュメントに残すことで検索のヒットもしやすくなり、後から見返す時も探しやすくなります

bot作成してslackでかんたん確認

f:id:sakura818uuu:20191217185035p:plain:w450

定期的に確認したほうがいいデータだと思ったので、botを作成しました。
redashのデータを定期的にslackに通知することで、最新の情報をかんたんに確認することができます。

botの作成には色んなエンジニアさんが手伝ってくれました。ありがとうございます。

bot警察をしてデータを見る文化を作る

f:id:sakura818uuu:20191217191830j:plain

弊社のslackにはbotが何十個もおり、いくらかんたんに見れるといっても見過ごしてしまうことも多いです。
どうにかこのデータを見る文化を作ることはできないか、と考えました。

そこで、botが通知してくるデータを私自らが解釈・要約して投稿することもしていました。
botの内容に徐々にスタンプがつき、返信がつき、最近では私以外のメンバーが能動的に反応してくれることも多いです。 (すごい!)

まとめ

本記事では、分析データを社内に情報共有するまでにどんなことをしたかを赤裸々に紹介しました。

まとめとして、この経験から学んだ情報共有の五箇条を記しておきます。

f:id:sakura818uuu:20191218073226j:plain:w430

「情報共有難しい…💭」
と悩んでいる方の参考に少しでもなれば幸いです。





最後に告知です。delyではエンジニアを絶賛募集中です。
ぜひお気軽にご連絡ください。

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