2018年も開発合宿を行いました

こんにちは、エンジニアの id:ymrl です。先日行われたfreeeの開発合宿の様子をご紹介します。

合宿先での集合写真

毎年恒例の合宿

freeeでは毎年秋に開発メンバー(エンジニア、デザイナー、プロダクトマネージャー、etc)全体で開発合宿をやっていて、今回で3回目です。毎年の恒例行事となっています。

開発合宿では毎年、開発メンバーがメインタスクから少し離れ、日頃感じてきた課題に2日間フルに集中して取り組み、プロダクト自体の改善や生産性向上に寄与することを目的としています。そのために開発以外の社内のメンバーにも協力をしてもらい、可能な限り割り込みが起きないようにして課題解決に集中できる環境になるようにしています。

例年、希望者はオフィスを飛び出して合宿先に宿泊しています。今年はCOLONY箱根さんにお邪魔しました!

colony-hakone.com

合宿先に行かないメンバーも五反田や大阪のオフィスで、なかには箱根の合宿先とリモートで協働して取り組んだメンバーもいました。

合宿先の様子

COLONY箱根のアクティビティスペースは開放的な雰囲気で、テーブルやソファなど、それぞれが好みの場所を見つけて作業していました。去年までの合宿であれば「宿に着いたらまずは電源とLANの設営」という感じでしたが、今回は全館Wi-Fi完備で電源もあちこちに設置されているということですぐに作業に入ることができました。ドリンクが無料なのもありがたかったです。

アクティビティスペースを上から撮影した写真 テーブルに向いあって作業している写真 ソファーに並んで座って作業している写真

客室のそばには会議室も用意されていて、そこに籠もって作業する人もいました。

会議室に籠もって作業している写真

高い天井と大きなガラス窓があって開放感のある雰囲気でした。

アクティビティスペースを横から撮影した写真 アクティビティスペースを横から撮影した写真 カウンターで相談しながら作業している写真

当日はあいにくの天気で、ときどき強く雨が振る場面もありましたが、雨が止んでる瞬間を狙って外に出て作業する強者もいました。

中庭で作業する人の写真 喫煙所でリラックス中の写真

最近「キーボードにこだわっている会社」と思われがちの弊社ですが、もちろんキーボードにこだわりのある人は持ち込んでいます。

自作キーボードを並べた写真 分割キーボードの写真

夕食も豪華でした。10月なのでデザートはハロウィン風味です。

夕食の魚のお造りの写真 夕食のデザートの写真。お化けとジャックオランタンの飾りつき 夜の作業風景の写真

写真をお見せできないのが残念ですが、温泉もとてもよく、しかも夜に行くと窓にプロジェクションマッピングが投影されていて、温泉から出てきたみんなが口々に「控えめに言って最高」と言いながら出てきました。私も入りましたが、控えめに言って最高でした。

COLONY箱根のみなさま、どうもありがとうございました!

おわりに

今年も無事に開発合宿を終えることができました。年々、freeeという会社自体も開発チームもどんどん規模も大きくなってきているわけですが、それでもこうして全員で2日間をフルに集中する機会を作れているのはすごいことで、これからも続けていきたいなと思います。こういうことができるのも会社全体の理解と協力があってのことで、ありがたい限りです。

今回の合宿では、また100個以上のプロジェクトが立ち上がり、これからどんどんfreeeのサービスが良くなったり、あるいはサービスを産みだしていく私たち自身の効率が良くなることでユーザーのみなさまに価値が届いていくはずです。どうぞご期待ください。

「第51回 情報科学若手の会」に参加してきました。

会計フリーのエンジニアをしている id:him0 です。2018/10/06~08 に軽井沢で行われた、「第51回 情報科学若手の会」に社会人2年目の若手ということで参加してきたので、そのレポートを書きたいと思います。

f:id:him0:20181011002933j:plain

f:id:him0:20181011002936j:plain

若手の会とは

情報科学若手の会は、情報処理学会の下部組織で、「情報科学に携わる学生、若手研究者、社会人のディスカッションと交流の会」ということで、年に1回合宿形式の発表会を運営している組織だそうです。運営は参加者がリレー形式行っており、今回が51回目ということで50年以上の歴史があるようです。すごい

発表内容の分野は、互いの交流を深めることで新たな発想が生まれることを期待し、情報に関わる幅広い分野から募る形を取っており、今年の発表内容は、ネットワーク系、セキュリティ、アルゴリズム、機械学習、量子コンピュータ、Web から、データセンター(物理)までホントにさまざまでした。

参加者層に関しては、社会人と学生の割合が1:1で、中には高校生と自称若手(本人たち談)が数名という構成でした。

freee はスポンサーというかたちで、参加させていただき、自分はスポンサー枠での発表を行いました。

こんな発表がありました

自分が気になった発表を紹介したいと思います。

リバースエンジニアリング

speakerdeck.com

難しくて一部しか理解できなかったので、下手な感想は言えないのですが、難読化とコンパイラ振る舞いは深い関わりがあることが分かりました。全く知らない世界のことが聞けて面白かったので、じっくり資料を再度見直してみようと思います。

コンテナデータセンタ

データセンターが所有したいという気持ちから、コンテナ買って、建築法調べたり、土地買って、内装作って、サーバ入れて...圧倒的な行動力に驚きました。まさに情熱

我々が普段使っているクラウドリソースも神の御業で提供されているわけじゃなくて、裏側ではこんな文字通り泥臭い作業が行われているんだよなと考えさせられました。

量子コンピュータ

量子コンピュータに対するふわふわしたイメージを整理するような内容で、分かりやすく興味深かったです。

量子コンピュータで扱うことができるという問題は、汎用コンピュータで可能な処理の中でも、限られており、量子コンピュータはアクセラレーションユニットとして使うことが主流になりそうだということで、自作マシンに GPU 感覚で、量子コンピューティングユニット刺すとか、PaaS で量子コンピュータリソースを借りるみたいな未来が来るのかなーと妄想していました。

CTF (Capture the flag)

CTF というものの存在は知っていたのですが、規模感や研究成果からのスピード感、0 day Attack の発見など、第一線にいる方からそのような話が聞けたのは興味深かったです。

参加者は、ほとんど学生で、社会人だと CTF の訓練する余裕ないという話は、なるほどなと思いました。

脳科学と深層学習

脳科学が Neural Network の発想を生み、その実装の再現が脳科振る舞いの解明にひらめきを与えているという相互作用の話は聞いていて非常にワクワクする話だなと思いました。

脳の振る舞いの未知の部分がまだまだあって、まだまだ脳と同じ振る舞いという次元にはただどり付けないという話で、まだまだ機械学習の発展余地はあること、また、人間の脳ってすげええって思いました。

高校生のLT

実際に問題解決のために、物理デバイスを作る話だったり、ソフトウェアを作る話だったりと高校生がこんなばりばりものづくりする時代なのかと、真の若手の勢いにすごく驚きました。

こんな発表をしてきた

スポンサー枠ということで、発表時間をいただいたので、自分はエンジニアが増える中で、どうやって開発速度を上げていくか、会計フリーの開発チームが取り組む「開発速度を支える取り組み」の紹介を行いました。

speakerdeck.com

互いの交流を深めることで新たな発想が生まれる

これからの進路を今考えているという学生の方もいて、いろいろな進路に進んだ先人からいろいろ聞いてこれからを決めたといった言ったのが印象的でした。

自分の話をすると、深層学習の特性等の話はプロダクトに活かせるのでないかと思ったので、理解を深めたいと思いました。

感想

感想ブログ書かれた方に「社会人が学会発表の場の空気を思い出すいい機会」という表現をみましたが、まさにそれだなという感想です。それ見たらそれ以上の感想出てこなくなった。

真の若手のコンピュータ知識の水準がものすごく上がっているのを感じて、自分ももっと勉強しないとなとという気持ちが高まりました。

内容の深い発表もありつつ、交流イベントもプログラムに入っており、参加してとても満足のイベントでした。

久々の登壇で少し緊張もしましたが、現場でやっていることを学生に共有し興味を持ってもらえたのは、貴重な体験なのかなと思いました。

参加者の方も含め、freee の開発の現場が気になる、実際インターンしてみたいという方は、気軽にお声掛け下さい。ではでは

デバッガでRedisのコードを読んでみよう

こんにちは、エンジニアの松崎 啓治(まつざき けいじ)です。
インターネット上ではこのIDで活動しています。 @futoase

先日、社内でエンジニア向けに「デバッガでRedisのコードを読んでみよう」というテーマの勉強会が開かれました。せっかくの機会なので、その内容をご紹介します。

勉強会スライドへのリンク

デバッガでRedisのコードを追いかけるメリットとしては以下のようなものがあります。

  • gdbを使ってRedisのコードをstep実行することで、どのタイミングでRedisのStorage(memory領域)からデータを取得できるのか体験から学べる
  • Redisだけではなく、nginxやMySQL、PostgreSQLなどgdbを利用してstep実行を行えるものであれば、今回の勉強会の手法を元に同じように体験から学ぶことができる

デバッガで追いかけるための準備

プレゼン資料で取り上げられている環境はLinux (ディストリビューションはUbuntu)ですが、公開されているDocker imageを利用することで、docker for Macやdocker for Windowsなど、非Linux環境でもRedisのデバッグ体験を行うことが可能です。

Docker imageの準備

プレゼン資料を作成した浅羽により、Redisのデバッグ環境を行えるDocker imageを作成するためのDockerfileをGithubにて公開しています。

github.com

また、Docker imageについてDocker Hub上に公開しています

docker コマンドを利用し、docker pullを行いましょう。

> docker pull futoase/redis-debug-4.0

docker imageの取得が終わったら、docker runコマンドでdocker containerを立ち上げましょう。

> docker run -it -p 9876:9876 \ 
  --privileged --cap-add=SYS_PTRACE \ 
  --security-opt seccomp=unconfined \
  futoase/redis-debug-4.0:latest /bin/bash
root@f76f0abef015:/# 

docker runに渡している各種オプションは、ptrace システムコールを呼び出すために必要なものとなっています。1

Redis Serverを立ち上げる

早速、先程立ち上げたcontainer内で、Redis Serverを立ち上げましょう。

root@c2407feddaa5:/# cd /root/redis-4.0.11/src
root@f76f0abef015:~/redis-4.0.11/src# 
root@01789e2f2a4e:~/redis-4.0.11/src# ./redis-server --port 9876 --protected-mode no --daemonize no
12:C 28 Sep 07:23:21.739 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
12:C 28 Sep 07:23:21.740 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=12, just started
12:C 28 Sep 07:23:21.740 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 9876
 |    `-._   `._    /     _.-'    |     PID: 12
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

12:M 28 Sep 07:23:21.745 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
12:M 28 Sep 07:23:21.745 # Server initialized
12:M 28 Sep 07:23:21.747 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
12:M 28 Sep 07:23:21.748 * Ready to accept connections

gdbを利用しRedis Serverに対してattachをする

Redis Serverに対してattachを行います。今回、gdbではなく、cgdb2を利用します。 今度は、docker execコマンドを利用し、先程立ち上げたdocker containerでcgdbを立ち上げます

> docker ps | grep redis-debug
f76f0abef015        futoase/redis-debug-4.0:latest   "/bin/bash"              11 minutes ago      Up 11 minutes       0.0.0.0:9876->9876/tcp               peaceful_chebyshev
> docker exec --privileged -it f76f0abef015 /bin/bash
> cgdb -p 12 # 12はredis-serverのprocess id で、先程redis-serverを起動したときにterminalで表示されたもの

cgdbの起動が終わると以下のようになります。

cgdbが起動した様子のスクリーンショット

この状態で、プレゼンにあるsetCommandにbreak pointを貼ってみましょう。

(gdb) b setCommand
Breakpoint 1 at 0x558b0346b63b: file t_string.c, line 98.
(gdb) c
Continuing. 

合わせて、redis-clientを起動します。起動する対象は、docker containerを立ち上げているホストマシン、 例えばあなたがMacBookを利用して立ち上げているなら、そのMacBookのターミナル上で立ち上げます。

ターミナルにコマンドを打ち込み、docker container上のredis-serverに接続しましょう。

> redis-cli -p 9876
127.0.0.1:9876>

合わせて、SETコマンド 3を redis-clientから発行してみます。

127.0.0.1:9876> SET hoge 1234

この時、cgdb側で特定のbreakpointで処理が止まっている状態になります。

スクリーンショット:breakpointで処理が止まり、画面上部にはブレークポイント周辺のコードが表示されている

この時、next コマンドや、step コマンドを実行することで、next実行(関数レベル)、step実行(関数実行をネストして見る)ことが可能になります。

スクリーンショット:nextやstepコマンドを実行している様子のgifアニメ

cgdbを利用し、関数の実行処理を追いかけることで、ソースコードリーディングに対し C言語未経験者でも読みといていくことが可能となります。

p コマンドを利用することで、ランタイムで評価中の変数の値について確認することもできます。

スクリーンショット:pコマンドでretval変数の値を確認している

ミドルウェアのソースコードを読む体験

MySQL、nginx及び今回のRedisなど、ミドルウェアのソースコードをgdbを利用し、 読む体験を行うことでどの処理にボトルネックがあるのか、どのタイミングでwhile loopに割り込みが入るのか など順を追っていくことができるようになります。このような体験を得るために、今回のように環境そのものをDocker image化し、 ソフトウェアインストールなどの設定をしなくても済むようにすることで、気軽に体験できる点がよかったです。

freeeのiOSアプリをSiri Shortcutsに対応させた話

こんにちは。モバイルエンジニアの高野です。

iOS 12がリリースされましたね!様々なアップデートがありますが、とりわけ目立って幅広いアプリで活用できそうなのはやはりSiri Shortcutsではないでしょうか。

ということで、弊社のiOS版クラウド会計freeeでも早速Siri Shortcutsに対応したバージョンを本日リリースしました!

Developers blogですので今回はどのようにこの機能を開発していったかを紹介します。

どんな機能?

Siriに「口座を同期して」と話しかけて口座の同期を開始する様子

弊社のプロダクトには、クレジットカードや銀行口座の明細をAPIなどから取得する同期機能が備わっており、定期的にバックグラウンドで明細取得されます。しかし、任意のタイミングで明細を取得して、最新の状態で会計処理をしたい時もしばしばあります。

今回はこの機能をSiri Shortcutsに対応させて、好きなタイミングでSiriを使って簡単に明細取得をできるようにしました。

Siriに「口座を同期して」と話しかけると、登録してあるクレジットカード・銀行口座の同期を開始し、新しい明細の取得が完了したらPush通知で知らせてくれる、という体験になります。

もちろん、Shortcutに対応させたことで、Siriに話しかける方法だけではなく、Spotlightのサジェスト・場合によってはロックスクリーンにもShortcutが表示される(ロックスクリーンに表示される条件はブラックボックスですが)ことになります。

WWDCのセッションの中で、Shortcutとして提供する機能はアプリ内で繰り返し行われる重要な機能が適していると言及されていましたが、今回それにピッタリの題材になったかなと思います。

Siri Shortcutsに対応させるために行うこと

ここから、今回の機能のために必要だった作業の流れを紹介していきます。

まずSiri Shortcutsに対応させるための開発には、SiriKitを利用します。SiriKitにはIntents frameworkとIntents UI frameworkが含まれています。

対応するにあたって参照したドキュメントは以下です。
SiriKit | Apple Developer Documentation

また、Appleが提供するサンプルコードであるSoup Chefも参照しました。
Soup Chef: Accelerating App Interactions with Shortcuts | Apple Developer Documentation

Intentの定義

さて、ではまずはIntentを定義します。IntentというのはSiriが受け付けられるリクエストのことを指します。

今回は「口座を一括同期する」と言うIntentが必要なわけですが、システムが標準で提供する特定ドメイン(MessagingやPayment等)のIntentとは合致しないため、カスタムインテントを作っていきます。

Intent Definition fileという新たに追加された形式のファイルを使って、Intentのタイトルやサブタイトル、パラメータ、リクエストに対してのレスポンスを定義していきます。このファイルはXcode 10~の「File > New > SiriKit Intent Definition File」から作成できます。

Intent Definitionを作成している様子のスクリーンショット

今回の定義は非常にシンプルで、タイトルや説明文などを記述しているだけです。CategoryにStart・Do・Run・Goなど汎用的な物が指定できるため、幅広いアプリでSiri Shortcutに対応させることができますね。

Intent Definition fileでIntentの内容を定義してからビルドすると、Intent Definition fileの内容に基づいたprotocolやclassを定義するコードが自動生成されます。 このコードのコンフリクトを避けるため、Intent Definition fileを開いた状態にし、XcodeインスペクタのTarget Membershipパネルで

  • 共有Framework(詳しくは後述します)の設定を”Intent Classes”
  • App、App Extensionの設定は”No Generated Classes”

と設定します。そうすることで、共有Frameworkに向けてのみコード生成されるようになり、コンフリクトが避けられます。

Intents App Extension

次に、Siri経由のリクエストをハンドリングするためのApp Extensionを用意します。

ユーザーからのリクエストに対して常にアプリを起動して反応する場合、このApp Extensionを作る必要はありません。ですが、ユーザーのリクエストに反応して何らかの処理をバックグラウンドで行いたい場合は、このIntents App Extensionを用意する必要があります。
バックグラウンドで処理を完了できれば、ユーザーはそれまで表示していた画面から離れることなくアクションを実行でき、より良いユーザー体験を提供することができるため、基本的にはIntents App Extensionを用いてバックグランドでタスクを完了できるようにした方がいいのではないかと思います。

Intents App Extensionの役割の大部分は、Siriとアプリが提供するShortcutを機能させるロジックとの橋渡しになります。今回私が実装した内容も、部分的に省略していますがだいたい以下のようなレベルの簡素な物です。

import Intents
import OurPrivateFramework

class IntentHandler: INExtension, FreeeFetchWalletableTransactionsIntentHandling {
  override func handler(for intent: INIntent) -> Any {
    return self
  }
  
  func handle(intent: FreeeFetchWalletableTransactionsIntent, completion: @escaping (FreeeFetchWalletableTransactionsIntentResponse) -> Void) {
    // 口座同期を開始するAPIにリクエストを送る
    APIClient.callTheAPI { success in
      completion(FreeeFetchWalletableTransactionsIntentResponse(code: success ? .success : .failure, userActivity: nil))
    }
  }
}

Siriからの要求をハンドリングするメソッドが、自動生成されたprotocolで定義されているので、そのメソッドの中で共有Frameworkに実装されたロジックを実行する感じです。
前述の、Intent Definition fileのスクリーンショットに「User confirmation required」という項目がありますが、Shortcutの実行前にユーザーに確認を促すべきアクションなどの場合はこれにチェックを入れ、IntentHandlerでconfirmするメソッドを実装する形になります。

注意点として、UIApplicationDelegateapplication(_:continue:restorationHandler:)はIntents App Extensionを提供しないアプリにおいてSiri経由のリクエストハンドリングする場合にも呼び出されるAPIですが、仮にIntents App Extensionを用意していたとしても、バックグラウンドでの処理ができなかった場合などに対応するため、application(_:continue:restorationHandler:)は実装するように、とドキュメントに書かれています。

Shared Framework

次に、AppとApp Extensionの間で共有する機能をこの共有Frameworkに実装します。「Intentの定義」のところで少し触れた共有Frameworkのことですね。Intent Definition fileを元に自動生成されるコードも、前述したTarget Membershipの設定を変更し、このFrameworkに含まれるようにします。

弊社のアプリでは、Siriから実行するための口座同期を開始するAPIの定義などがこのFrameworkに含まれています。

Siri対応に限らずApp Extensionを提供する際にはいずれにしろこのようなFrameworkが必要になることが多いですし、仮にApp Extensionに対応していないアプリでも、サービスのコアとなる機能をこのレイヤーに切り出しておくと設計としても良いのではないかと思います。

ShortcutのDonation

最後の仕上げとして、Shortcutとして提供したい機能をSiriに提供します。アプリ内でSiri Shortcutsに対応させる機能が利用される度にDonationするコードを実行します。ドキュメントによると、この時の時刻や位置等の環境を元にSiriがサジェストしてくれるようになるということです。

ただし、Siri経由でその機能が実行された場合は、システムは暗黙的にそのことを認知するようで、明示的にDonationする必要なありません。
逆にユーザーが一度も行ったことのないアクションを提供はしてはならず、将来的にユーザーが行う可能性の高いアクションについてはRelevant ShortcutsとしてSiriに提供するようにと書かれています。

アクションは、NSUserActivityINInteractionを使ってSiriに提供できますが、今回はINInteractionを使って、以下のようなコードでDonationしました。

let intent = FreeeFetchWalletableTransactionsIntent()
INInteraction(intent: intent, response: nil).donate { _ in }

エラー処理など省略していますが、Donationするのに最低限必要なコードはこれだけです。
これを、アプリ内で口座の同期ボタンがタップされる際に実行しておくようなイメージです。

Add to Siri

さて、ここまで行えばSiri Shortcutsには対応できていて、SpotlightやロックスクリーンへのShortcut表示は行われる下地が整った状態になります。 ここで更にSiriらしく、アプリ内で任意の音声フレーズを今回作成したShortcutに割り当て、音声でShortcutを実行できるようにする方法を紹介します。

まずはIntents UI frameworkに含まれるINUIAddVoiceShortcutButtonを使って、Add to Siriボタンを画面に表示します。
INUIAddVoiceShortcutButtonのイニシャライザは、enumとして定義されるINUIAddVoiceShortcutButtonStyleを引数として受け、それに応じてボタンの外観を変更します。現時点ではblack, blackOutline, white, whiteOutlineが定義されており、その中からアプリに合う物を選ぶことになります。

let button = INUIAddVoiceShortcutButton(style: .white)
view.addSubView(button)

表示はこのようになります。

Add to Siriボタンのスクリーンショット(白背景と黒背景)

INUIAddVoiceShortcutButtonのdelegateを設定しておくと、このボタンがタップされた時にdelegateのpresent(_:for:)メソッドが呼ばれます。その引数に渡されるINUIAddVoiceShortcutViewControllerを表示することで、フレーズを登録する画面がをユーザーに提供することができます。すでにフレーズが登録されている場合は自動的にボタンのラベルが変化し、ボタンをタップすると、編集画面を起動するためのpresent(_:for:)メソッドが呼ばれます。

現時点でINUIAddVoiceShortcutButtonのリファレンスに載っているサンプルコードだと、ボタンにaddTargetで設定したセレクタでINUIAddVoiceShortcutViewControllerインスタンスを作って画面に表示している箇所があり、この理由は分かりませんが、delegateを使ったほうがシンプルに書けると思います。

まとめ

大まかにではありますが、会計freeeでSiri Shortcutsに対応した際の流れを紹介しました。

弊社のモバイルチームではHack dayという、いわゆる20%ルール的な制度を設け、その中でエンジニアが自律的に作りたいものを作っていけるようにしています。実は今回のSiri Shortcuts対応はその中から生まれた機能です。この制度を使ってこれまでに色々な機能のリリースや、開発基盤の整備などが行われています。

ということで、freeeのモバイルチームではやっていきによってfreeeのプロダクトをもっとよくしてくれる仲間を募集しています!

スモールビジネスの未来をアプリで切り拓くモバイルエンジニア募集! - freee 株式会社のモバイルエンジニア中途の求人 - Wantedly

jobs.freee.co.jp