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

複数人でPodcastを収録するときに便利なアプリを作ってみた

iOSアプリエンジニアの@hiragramです。普段は美容情報アプリVICOLLEを作っています。

先日のSpeeeKaigiで"複数人でpodcastを収録するための便利アプリを作ってみた"という発表をしました。

最近いろいろ新しいpodcastが出てきて、参入障壁が下がっていることは良いことだと思うんですが、音質が悪いとか、高音が耳にキツいとか、そういう問題が多いように感じていました。また、複数人で収録するとなると、Skypeでまとめて録音するのか、各々が録音したものを誰かが編集するのか、後者だとしたらそれってどうやるのか、といった問題が発生するでしょう。

そこで、録音からミックスまで簡単に行えるMacアプリを作って発表してみました。

AudioToolboxで録音するに当たって登場したSwiftのポインタの話

マイクからオーディオを録音する所にはAudioToolboxを使いました。

AudioToolboxのAPIはポインタを介してデータをやり取りするものが多いです。今回はじめてSwiftでポインタを扱ったのでまとめました。

UnsafeMutablePointer

  • 多分一番やばいポインタ ポインタが指すデータの型なし(untyped)
  • 名前にやばそうな単語が多すぎ
  • どっか間違えてもBAD_ACCESSと言われるだけなことがおおい、デバッグ手がかりなし

OpaquePointer

  • Swiftの世界に出てこれないCのやばい構造体を扱うためのラッパーっぽい
  • これもまたデータ型なし(untyped)

UnsafePointer / UnsafeMutablePointer

  • やっと型が! UnsafePointer<Pointee>
  • pointeeプロパティから対象のオブジェクトにアクセスできる
  • 型があるだけで安心感がすごい

AVFoundationでミックスダウン

このアプリでは、録音ボタンを押すタイミングを補正するために、ボタンを押した時刻のタイムスタンプを音声データと一緒に保存しています。

よって、複数の録音データをタイムスタンプに応じてずらしてミックスダウンする必要があります。

処理の流れとしては、

  • info.plistからタイムスタンプを読み込む
  • 一番最初に録音開始した音源を基準に、差の分だけずらしながらオーディオトラックを作る
  • AVMutableCompositionをつかって1トラックにまとめる
  • AVAssetExportSessionをつかってm4aファイルにエクスポート

所感

Macアプリ + 音声処理というあまり情報がない分野に取り組んでみました。 作成したアプリはコードを公開しているので、もうちょっとコードきれいにしたら使ってみてくださいという気持ちです。

GitHub - hiragram/Mitsuami

管理画面チラ見せ♡ナイト #4 に登壇しました

f:id:kohtaro24:20170329110934j:plain

新卒2年目エンジニア(もう少しで3年目)のkohtaro24です。

普段はライフスタイルメディア事業でヌリカエというサービスに関わる全般的な機能設計/開発を行っています。

プライベートでは最近ゼルダにハマっているのですが、3週間くらい経つのに神獣を未だ一匹も倒せていません。いったい何がおかしいのでしょうか。

本題

今回、3/24に開催された管理画面チラ見せ♡ナイト #4に恐縮ながら登壇させていただきました。

100名あった参加者枠(後に120名まで増枠)がイベント公開の翌日には埋まっているほどの人気イベントで、メルカリさんやクックパッドさんをはじめ、名立たる企業の方々が登壇されている中に自分が飛び込むのは非常に緊張モノでした。

以下はイベント概要の引用です。

各企業が独自で開発しているWebサービス管理画面。

お問い合わせ対応やKPIのモニタリングなど、大事な要素が詰まっている部分ですが、なかなかその部分が共有されません。そこで各社のどんな管理画面を使っているのかを発表し合うはこびとなりました。ご好評をいただきまして、#4を開催いたします!

サービスの運用には細かいPDCAがどんどん蓄積されていくので、管理画面の機能も積み上げで大きく複雑なものになっていくイメージがあったりしますね。

特にヌリカエのようなBtoBtoC型のメディアはtoCもtoBも意識しなければならないので、運用に関わる変数も多く、管理画面の設計には頭を悩ませることが多いです。他の会社はどうなんだろうな〜とか思うこともあるので、こういうイベントの存在はウレシイですね。

発表内容

f:id:kohtaro24:20170329103913j:plain

今回の発表では、ヌリカエのCS領域における架電運用の課題解決をテーマとし、架電ツール「TelTelBows」の開発に至る経緯の話をした上で、発表の終わりにツールのデモを披露しました。

発表内容の要点を絞るとこうなります。

  1. ヌリカエにおけるCSは、事業収益を支える対カスタマーコンサルティング業集団(Customer Sales)という位置付けである
  2. そのため、Web上から問い合わせしてきたカスタマーに対し、CSがどれだけ効率的に返答架電のアクションができるかが重要な指標となっている
  3. 現状の架電リスト作成形式の運用方法は、1架電ごとに細かい手間が入るため、積み上げで工数問題になっている
  4. この運用方法が採られている理由は、いくつかの運用上の制約に由来するものだと考えられたため、本来存在する制約を一通り洗い出した
  5. 洗い出した制約を担保できる機能を、架電ツールという形に落とし込むことにより、架電リスト運用を廃止する
  6. このツールの開発により、CSの1架電辺りに費やされる人的工数は、概算で10分の1まで落とせる見込になる

以下が今回の登壇で使用した発表資料です。デモ動画もあるので是非ご覧ください。

ヌリカエのCS(=Customer Sales)の事業的立ち位置についてはWantedlyの募集記事にも記載されているので、興味のある方はこちらもどうぞ。

雑感

プレゼンやってみての所感

懇親会で参加者の方々との交流の機会があり、「プレゼン面白かった」とのコメントを多くいただきました。大変ありがたい思いです。

特に架電ツールのデモに対する反響が多く、ツールが自動で電話を架け続けてる光景は視聴者に夢を与えるらしいです。 動画入れておいて本当に良かった。

現状の運用をベースに効率化を図ろうとするのではなく、現状の運用を捨てられない理由は何か(=制約は何か)を最初の問いにしたことが今回の改善策に繋がったと感じているので、今回のプレゼンではそのプラクティスを伝えられていればよいなと思います。

色んな参加者がいる

イベント対象者がWebサービスの管理画面を改修する権限がある方ということもあり、ディレクター/エンジニア/デザイナーをはじめ、色んな職種の参加者が来訪していた印象です。

興味の方向に関しても、サービスのKPI/運用の裏話/テクノロジー/デザインなど参加者ごとにそれぞれ少しずつ違っていて、こんなに参加者が多種多様なイベントは珍しいのではないでしょうか。

管理画面から読み解ける情報って本当に様々なのだなぁと実感しました。

ダッシュボードツールの人気

re:dashやchartioなど、ダッシュボードツールの採用割合高いなぁと。

導入が割りとすぐできて、必要なデータさえあれば柔軟に指標を可視化できるし、複数のデータソースに対応している。KPIが変則的になりがちなスタートアップ事業との相性がすごく良いのかもしれないですね。

ダッシュボードを内製で作らないという選択肢に強く貢献しているなぁというのを実感しました。

独特なタイトルコール

司会のぁゃぴさんが「チラッ♡」と呼びかけて、参加者が「見せナイト〜!」と大声で応える形式。 このイベントの名物的なモノだと思ってるのですが、みんな恥ずかしがりながらやってる感じが面白いですね(笑)

この幕開けの直後、マジメなプレゼン内容にすぐさま意識を引き戻される感じがなんかツボです。

最後に

貴重な登壇の機会をいただき、ありがとうございました!

今回の学びを現場の管理画面開発に還元し、更なる改善に向けて切磋琢磨していきたいと思います。 いずれまた発表できるといいな。

宣伝

事業に対して最適な管理画面、最適なソリューションを提供する上で、一緒に可能性を模索/推進していける方も募集しています!

↓↓↓

www.wantedly.com

魔法の世紀の片鱗(勤怠打刻を頑張らない話)

Tei1988です。 前回のSpeeeKaigiでは、最寄り駅検索APIをつくってみた話を発表しました。

今回のSpeeeKaigiは、魔法の世紀の片鱗という題で、勤怠打刻を頑張らない話をしました。(SpeeeKaigiについてはこちら。)

落合陽一さんの書かれた魔法の世紀という本の冒頭付近に、カームテクノロジーという言葉が出てきます。 このカームテクノロジーは、人にテクノロジーを使っていることを意識させないようなテクノロジーという意味合いだそうです。

今は勤怠を正しく付けるために人間が打刻を頑張っていることが多いと思うのですが、そこにカームテクノロジーが加わるとどう変わるんだろうかというのが、今回の発表のネタです。

※ただ、もっと話を進めていくとそもそも出社とか勤怠とかみたいな話までいってしまいそうなので、勤怠を正しく付けることにフォーカスを当てました。

発表資料は以下になります。

speakerdeck.com

質疑では「会社に近づいただけで出社ってどうなの?」であったり、「外出から直帰するような人はどうするのか?」といった、出社/退社の判定方法に関して質問をいただきました。 今回はGPSで簡易的に行ったので、精度の問題や会社周辺に居ない場合などの例外には対応できませんでしたが、人が打刻を頑張らない方向で、より適切な判定方法があれば、そちらを使いたいです。

感想

今回初めてAWSのAPI Gateway, Step Functions, Lambdaを使ったのですがとても扱いやすく、良いなぁ、と思いました。 Serverlessも扱いやすさの印象にかなり貢献してそうです。

当初は、Serverlessだけを使ってAPI Gateway + Lambdaで行おうと考えていました。 ただ、出社APIと退社APIで同じ処理を行う場所があり、それを処理毎にLambdaを分けたかったのですが、Lambda間の連携がちょっとややこしかったので諦めて、Step Functionsを導入しました。 今となってはですが、まだ要らないレベルの分割だったかもしれないです。

Step Functionsを使うことにしたので、API GatewayからStep Functionsを呼ぶことになりました。が、API GatewayからStep Functionsを呼ぶ際に、大きく2つハマってしまいました。

一つ目は、そもそもAPI GatewayからStep Functionsの呼び方がわからない!😨です。

LambdaはAPI Gatewayでも別枠でサポートされていたりして直ぐ分かったのと、Serverlessの設定で記述できたんで、とても楽だったんですが、Step Functionsは見つけられなかったんですよね…。

そんなときに、How can i call AWS Step Functions by API Gateway?がとても参考になり、無事設定ができました。

二つ目は、テスト環境ではバッチリ動くのに本番にデプロイしたら動かない!😨です。

原因は単純に設定ミスでした。API Gateway側の設定で「アクション」というパラメータに設定すべき値を間違えていました。 ただ、テスト実行の場合、この「アクション」を見ていないようで、その値が間違っていても実行されちゃっていました。 テストで動いて本番で動かないという…。 にっちもさっちも行かなくなり、再度上記ページを読み直したところ、間違いに気づき、無事本番でも動くようになりました。

前回のSpeeeKaigi同様、賞はもらえませんでした😨が、とても良い場でした🌸。

Forkwell Meetup #4 イベントレポート

こんにちは!エンジニア組織推進室の中野です。
3/18(土)のForkwell Meetup #4にスポンサーとして参加してきました! 実は前回もスポンサーとして参加しておりました。

▼前回の様子

Forkwell Press – 発表スライドまとめ − Productivity...

Forkwellさんにはいつも素敵な場をつくっていただき、感謝です!
インタビューもしてもらいました。よかったら見て下さい(^q^)

Forkwell Press – Speee 流『優秀なエンジニアを惹きつけるスカウトの秘訣』 / Forkwell Scout

f:id:kana-nakano:20170322183426j:plain

雰囲気

今回の会場はメディアドゥさんのオフィス。
お…おしゃすぎる…!広い~!!(走りたくなるぞ)

f:id:kana-nakano:20170320214037j:plain f:id:kana-nakano:20170322190058j:plain

他のスポンサー企業様はこんな感じ。(一部抜粋)
▼ヌーラボさん。ヌーラボラベルの日本酒…美味しそうだった~

f:id:kana-nakano:20170322190135j:plain

▼ネクストさん。ホームズくんのキュートさったら。

f:id:kana-nakano:20170322190156j:plain

Speeeはコーヒーをハンドドリップで提供しました。
“Speee Blend"という社員の嗜好に合わせたしっかりとコクがあり、冷めてくると後味に甘い余韻がある特注の豆でご用意しました!

f:id:kana-nakano:20170320220338j:plain f:id:kana-nakano:20170321230142j:plain

一緒に参加したエンジニアの@hatappi@pataiji(左から)。
Speee Blend、好評だったみたいで嬉しいです。提供追いつかなくて飲んでいただけなかった方、本当にすみません!もくもく会イベントでも提供しているのでぜひご参加ください(๑´ڡ`๑)

ゲストトーク

とにかく登壇者が豪華でした。非エンジニアの私でも知っておくべき大切な内容がたくさんありました。例えば…

  • 振り返りの進め方・雰囲気づくりが大事。KPT以外にも色んな振り返り手法があるし、むしろ同じ手法だと同じ観点からしか意見がでなくなり、みんなツラくなってくる。
    (Effective Retrospective アトラクタ @ryuzeeさんの発表)
  • ペアプロについて。書かれたコードを片っ端からコードレビューしていく。レビューは新鮮なうちにするのが良い、とのことですがこれはどんな仕事も一緒。最速でPDCAを回す劇薬。
    (ペアプログラミングの使いどころ タワーズ・クエスト @t_wadaさんの発表)

などなど。他にも為になる内容がたくさんあり、非常に勉強になりました!

LT&交流会

交流会のなかにLT発表が含まれていました。弊社からは@pataijiが発表しました! 皆さんお酒片手にしっかりLTを聞くという。笑

f:id:kana-nakano:20170322190229j:plain

まとめ

ブースに遊びに来てくださった方、ありがとうございました\(^o^)/
「Speeeさん最近どこにでもいるね~!(笑)」ってよく言われるんですけど、それだけ真剣に一緒に働く仲間の採用活動をしてます!まずはSpeeeのことを知ってほしい、その想いが強いです。本気で技術に向き合っている私たちSpeeeですが、もし興味を持ってくださった方は、ぜひ気軽にラウンジに遊びに来て下さい!お待ちしております♪

f:id:kana-nakano:20170320222914j:plain

HAProxyによるブランチ毎ABテスト基盤

こんにちは、新卒エンジニアの宮地(miyachik)です。
業務ではネイティブアド配信プラットフォーム UZOUの裏周りをやっています。

今回はSpeeeKaigiで発表した(フロントの変更なら)エンジニアの工数を必要とせず、アプリケーションの開発言語を問わない汎用的ABテスト基盤の話をします。 SpeeeKaigiについてはこちら↓

tech.speee.jp

前提

今回のABテスト基盤では

  • ブランチを分けた状態で個別にABテストができる(masterにマージする必要なし)
  • フロントの軽微な修正はエンジニアにはエンジニアの工数は割かない(ディレクターとデザイナーのみで行えるようにする)
  • API側などbackendのロジックに対するABテストも行えるようにする
  • 開発言語にとらわれずABテスト基盤導入をすることが可能

を実現することが出来ます。表側はRailsで裏側にAPIサーバーがいる、みたいなときにも試すことが出来ます。(簡単な変更のみならば既存のgemなどを使えば良いのですが、どうしても要件を満たせないことが出てきてしまうので…)

まずは最上段の振り分けについて話したいと思います。

やったこと

  • HAProxyによるABテスト振り分けと再抽選の防止
  • HAProxyの設定ファイルをRailsアプリケーションから動的に吐き出し、アプリケーションをデプロイとHAproxyの設定を再読込するタスクを作成
    • ABテストサーバをbackendから切り離し
    • 対象のABテストブランチをABテストサーバにデプロイ
    • 生成したHAProxyの設定を再読込
    • フロントのダウンタイムはゼロになるように

HAProxyについて

HAProxy とはプロキシサーバであり、ソフトウェアロードバランサーです。 HAProxyが何であって、何でないかは公式のドキュメントに書いてあります。 ドキュメントにもある通りHAProxyにはロードバランサーとしての機能があり、HAProxy自身がCookieを発行することができます。そしてCookieがセットされているかを判断することもできます。 また、HAProxy単体でABテスト振り分けに関する機能は実現可能なため、Front/backendのアプリケーションの種類は問われません。

インフラ構成図

ざっくりとした構成は以下です。各sideごとのサーバ台数はHAProxyのbackend定義により行えます。 f:id:tigger501st:20170315110949p:plain

ABテストパターンが反映されたブランチはab_sideにのみにデプロイされ、結果が芳しくない場合にはmergeせずに次のABテストに進むことが出来ます。

HAProxyによるABテスト振り分け

振り分けについてはHAProxyのACLとbackendの複数定義により行っています。

ACL(Access Control List)

公式ドキュメント HAProxyのACLは非常に柔軟なアクセスを振り分けることができます。 下記のように書くことでCookieを判断して振り分けるbackendを変更することが可能です。

    acl normal hdr_sub(cookie) ab-test-pattern=0
    acl ab-test-pattern hdr_sub(cookie) ab-test-pattern=1
    use_backend normal_side if normal
    use_backend ab_side if ab-test-pattern
    default_backend first_side

ab-test-patternというCookieが存在していない場合(初回アクセス時)には first_side に振り分けら、Cookieが存在しており && 値が1なら ab_sideへ、値が0なら normal_sideへ振り分けられます。

backendの定義

backendの定義は下記の様に行い、初回アクセス時にはCookieを挿入し、重み付け付きの振り分けに関してはweightで行います。この様にすればweightによってABテストサーバーに振り分けられたユーザはその証拠としてCookieの値として 1が書き込まれます。

下記の例ではnormal:AB = 75:25になっています。normalの確立 = ホスト名末尾が 0に行く確立の総和です。なので、設定を吐き出すときにはnormal_sideのweightは設定されている(normal_sideのホスト数)/(設定したいnormal側のweight)である必要があります。 デプロイされているアプリケーションのブランチが違うので、アプリケーション側で ab_side側かnormal_side側のアクセスなのかは判断する必要はありませんが、事故を防ぐ場合Cookieの値を参照することによりユーザがどちら側に抽選されたのかを判断することができます。 初回アクセス時にはCookieはセットされておらず、X-HOST-NAME を使用しHeaderからホスト名を参照しab_sideかnormal_sideかを判断することが出来ます。

backend first_side
    mode http
    cookie ab-test-pattern insert nocache
    balance roundrobin
    http-send-name-header X-HOST-NAME

    server web1-0 127.0.0.1:80 weight 25% check cookie 0 inter 1000 fall 2
    server web2-0 127.0.0.2:80 weight 25% check cookie 0 inter 1000 fall 2
    server web3-0 127.0.0.3:80 weight 25% check cookie 0 inter 1000 fall 2
    server web4-1 127.0.0.4:80 weight 25% check cookie 1 inter 1000 fall 2

あとはnormal_sideにはnormal側のホストのみを宣言すればnormalにしか行きません。 ただし、ab_sideにはnormal側のホストを含めて宣言しないと、万が一ABテストサーバ(今回の場合web4-1)が落ちていた場合に該当するホストが見つからずアクセスできなくなってしまうので注意が必要です。(check cookieをしている場合でもホストが落ちていると振り分けは行われず別のサーバへ振り分けられる)

以下が実際に吐き出されるファイルです。負荷などを気にする場合は適切にmaxconn等の設定を追記してください。ブランチ名はab-test-patternの想定です。 normal_sideのIPなどはRailsのconfigファイル内に配列で書いています。

global
    log         127.0.0.1 local2 info
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     10000
    user        haproxy
    group       haproxy
    daemon
defaults
    log     global
    timeout connect 60s
    timeout server 1m
    timeout client 1m
    timeout check  5s

# web
listen frontside
    maxconn 4000
    fullconn 4000
    bind 0.0.0.0:80
    mode http
    acl normal hdr_sub(cookie) ab-test-pattern=0
    acl ab-test-pattern hdr_sub(cookie) ab-test-pattern=1
    use_backend normal_side if normal
    use_backend ab_side if ab-test-pattern
    default_backend first_side

backend first_side
    mode http
    cookie ab-test-pattern insert nocache
    balance roundrobin
    http-send-name-header X-HOST-NAME

    server web1-0 127.0.0.1:80 weight 25% check cookie 0 inter 1000 fall 2
    server web2-0 127.0.0.2:80 weight  25% check cookie 0 inter 1000 fall 2
    server web3-0 127.0.0.3:80 weight  25% check cookie 0 inter 1000 fall 2
    server web4-1 127.0.0.4:80 weight  25% check cookie 1 inter 1000 fall 2

backend normal_side
    mode http
    balance roundrobin

    server web1-0 127.0.0.1:80 check inter 1000 fall 2
    server web2-0 127.0.0.2:80 check inter 1000 fall 2
    server web3-0 127.0.0.3:80 check inter 1000 fall 2

backend ab_side
    mode http
    cookie ab-test-pattern insert nocache
    balance roundrobin

    server web1-0 127.0.0.1:80 check cookie 0 inter 1000 fall 2
    server web2-0 127.0.0.2:80 check cookie 0 inter 1000 fall 2
    server web3-0 127.0.0.3:80 check cookie 0 inter 1000 fall 2
    server web4-1 127.0.0.4:80 check cookie 1 inter 1000 fall 2

HAProxyの設定変更はRailsアプリケーションから、指定したブランチのdeployはcapistranoで実現しました。

処理の内容としては

  • HAProxyからab_sideを切り離したconfigをreload
  • 指定したブランチをデプロイ
  • 生成したHAProxyのconfigファイルを再読込

です。HAProxyはgraceful restartが可能なので、デプロイによる表側への影響はありません。

まとめ

実現したこと

  • 既存の構成を崩さない形での振り分け器の導入
  • HAProxyによる、Cookieを使用したアクセス先サーバーへの制限(再抽選防止)
  • HAProxyの設定ファイルを自動書き出し&deploy時読み込み

実現できていないこと

  • オートスケールの考慮
  • deployする毎にインスンタンスのIPが変わる場合の対処
  • 完全なmasterとの同期システム

Q&A

Q.ABテスト用にカラムを追加したいどうする?

A.現状、表側の変更のみを考えているため、考慮していなかった。おそらくdeployフローでmigrationを用意しておくことで対策。

Q.Masterとの同期はどの程度で考えていますか?

A.複数のテストが平行して走る際は、deploy時にmasterとの同期考えているが、それだけではおそらく不整合が出てしまうケースがあるので、考慮が必要。考えきれていなかった。