カレーの恩返し

おいしいのでオススメ。

新卒ISUCONで優勝しました

新卒ISUCON(SHISUCON)とは

弊社ではwebアプリケーション開発の基礎となる知識を実践的に吸収するため、新人研修の一環として新卒メンバー+CTOでISUCONを行うことが恒例になっています。
このISUCONをSHISUCON(SHinsotsu ga Iikanjini Speed Up Contest)と呼んでいます。(他の人は新卒ISUCONと呼んでいます)

ルールは以下の2点を除けば本来のISUCONと同じです。

  • 競技時間が11:00~17:00と本番より2時間短い
  • 13:00~13:00, 15:00~15:30の計2回、ISUCON上級者のメンターがアドバイスをしにきてくれる

↓去年、一昨年のSHISUCONの内容

www.wantedly.com

www.wantedly.com

SHISUCONの意義についてはこれがわかりやすい

speakerdeck.com

今回のSHISUCONではYahoo!Y!SUCONを利用しました。
Y!SUCONは1台のサーバで解くことが想定されている問題ですが、今回は3台のサーバ(c4.large)が与えられました。

新卒ISUCONで優勝しました

新卒ペア*3 + CTOおひとりさまの4チームで戦い、自分は @spring1018 とチームを組みました。(新卒ではないけど別業種からの転職&本人の強い参加希望があったので新卒枠としての参加になったらしい?)

自分達のチームは24,550点でフィニッシュしCTOをおさえて優勝することができました。 自分達は結局サーバを1台しか使っていないのでY!SUCONと同じ状況でのscoreとなっています。
今まで行われていたSHISUCONではCTOが毎回優勝していたのでCTOから優勝の座を奪えてよかった✌️

f:id:euglena1215:20190512003038p:plain
青いのが自分のチーム

f:id:euglena1215:20190512005606p:plain
負けて体調が悪化するCTOの図

戦略

まず、自分も@spring1018もインフラエンジニアではないため制限時間内でのmiddlewareの完璧なチューニングは難しいだろうと考えました。 そこで 「競技時間中はインフラのことをなるべく考えずにアプリケーションに集中する、そのために80%のクオリティのチューニングはコピペで終わるような秘伝のタレを作っておく」 と話し合って決めました。

事前準備

過去問を解く

@spring1018は初ISUCONだったということもあり、問題形式に慣れることを目的にISUCON7予選を本選出場ラインのscoreが出るまで解きました。
(ネットワーク帯域の再現はしていないので正確ではない & 本選出場のscore届くまでに2日かかった)

自分はISUCONは参加したことがあったのですが、アプリケーションしか触ってこなかったのでインフラ周りの知識が皆無でした。
そのため個人的にISUCON6予選、ISHOCON2*1を解いてインフラ周りのハマりポイントに一通りハマっておくよう心がけました。

wikiに諸々の情報をまとめる

Home · wantedly/shisucon2019-teppei-haruki Wiki · GitHub

競技開始前からリポジトリを作っておき、wikiを見ればほとんども問題が解決することを目指し充実させました。
普通に便利なのでもうちょっとちゃんとまとめてブログの記事にしたい.

作業フェーズをリマインダーに設定しておく

f:id:euglena1215:20190512181402p:plain:h300
こんな感じ

人間は焦ってしまうと予定を忘れる傾向にあるので複数台使うかどうかの最終判断/再起動試験チェックなど忘れたら困るやつは予めリマインダーに設定しておきました。 これで時間のことを気にせず安心して改善に取り組めました。 作業フェーズもwikiに書いていた。

本番(時系列)

自分のやったことを時系列で書いていく、ペアの@spring1018がやったことは↓に記事のリンクが貼られるはず

spring1018.hatenablog.com

10:50ごろ 競技開始
真っ先にbenchを走らせて初期scoreを確認、確か1500点くらいだった気がする

10:58 ~/をgit管理下に

11:17 nginx, mysql, sysctlをgit管理下に移動

11:28 kataribe, myprofilerが動く状態になる
@spring1018がDB schemaの調査を終わらせてくれていたのでkataribe, myprofilerを見つつbenchを回した。
kataribeはこれ、myprofilerはこれ
kataribeから「この時点では静的ファイルもアプリケーションを介して配信していたのでnginxで配信した方がいいよね、ついでに304つけちゃおうか、ついでにnginxの秘伝のタレ流し込んじゃおうか」と判断。
myprofilerから「tweets系が明らかに遅い、一旦created_atにindex貼ってお茶を濁そう」という判断をした。(確かあんまりscore変わらなかったはず)

11:50 nginxの秘伝のタレを流し込む hiden nginx by euglena1215 · Pull Request #6 · wantedly/shisucon2019-teppei-haruki · GitHub
scoreはほぼ変化なかったけどkataribeががらっと変わって GET /が遅すぎるということがわかった
ISUCON序盤のはずなのに全然CPUを使ってなかったのでおもむろにunicornのworkerを1→2に増やしたら1500→1700になってDBのCPUがボトルネックであることがわかるようになった。

12:00すぎ アプリケーションの概要をきちんと把握する
ようやくボトルネックの箇所がわかるようになってきたので二人でアプリケーションの概要の整理をした

  • isuwitterとisutomoが2つに分かれている(DBも別)
  • tweetsのオーダーが10万なので重そう、GET /ではフォロワーのツイートだけでいいのに全員のツイートを取得している。無駄っぽい。
  • GET /でusers.nameを取得するためにN+1が発生している、直したい

12:30ごろ DBを1つにくっつける
初期実装ではisuwitterとisutomoの2つにDBが分かれていたのをisuwitter DBにfriendsテーブルをもってくることによって1つにくっつけた。
理由は以下の通り。

  • 今後2つのサービス(isuwitterとisutomo)をくっつける可能性がある、そうなったときには2つのDBとのconnectionを張る必要がでてきて2倍のconnectionが必要になる
  • 後半にテーブルの移し替えを行うとindexを貼り忘れるといった可能性がでてくる、なら何も手をつけていない今のうちにやっちゃえばよさそう

結局http通信による遅延がボトルネックになるところまでチューニングが進まなかったのでほとんど意味はなかった気がする。

15:03 GET /でフォロワーの最新50件のツイートだけを取得するようにする 1700→3800 where friend ids by euglena1215 · Pull Request #14 · wantedly/shisucon2019-teppei-haruki · GitHub
この修正に2時間かけてしまい、申し訳ねえ申し訳ねえと呻きながら修正したら3800に点数が上がってホッとした。

kataribeを見るとこんな感じにGET /が若干早くなってGET /hashtagGET /searchと同じくらいになった。
なので次はGET /のN+1改善とdef searchで実行しているクエリを絞るのをやっていこうという話になった。

↓は申し訳ねえ申し訳ねえと呻きながらbinding.pryしているときに送られてきた自分の部署のリーダーからのDM。絶対に許さない。

f:id:euglena1215:20190513011018p:plain
自分のscoreが伸びないことを喜ぶチームリーダーの図, 一番下が自分のチーム

15:28 GET /のN+1改善 3800→3941 global user hash by euglena1215 · Pull Request #16 · wantedly/shisucon2019-teppei-haruki · GitHub
全然伸びなくて :thinking_face: という感じだった。SHISUCON終了後にキャッシュをインスタンス変数からThread.currentに持ち替えたら50000→59000とガッと上がったので最初からThread.currentで保存するようにしていたらもっと伸びていたかもしれない。

15:32 def searchで実行しているクエリの取得数を絞る by @spring1018 3941→13311 change get_all_tweets by spring1018 · Pull Request #17 · wantedly/shisucon2019-teppei-haruki · GitHub
これが効いてかなり点数が伸びた。
kataribeを見るとこんな感じにまたGET /ボトルネックが戻ってきた。

この辺りから複数台構成を意識し始めて@spring1018に2,3台目のセットアップをお願いした気がする。

16:00 GET /でisutomoにアクセスしていたのを直接実行するように変更した 13311→14865 join GET / by euglena1215 · Pull Request #11 · wantedly/shisucon2019-teppei-haruki · GitHub

この辺りで@spring1018が2台目のサーバの/etcを全消去するというアクシデントが発生し、2台目は復旧不能になってめちゃくちゃ面白かった。
一応3台目もセットアップするようお願いしたけど、さすがに時間が間に合わず最後まで1台のサーバで動かすことになった。

16:15 tweets tableにuser_id, created_atの複合indexを貼った 14865→23914 myprofilerでスロークエリを確認するとSELECT * FROM tweets WHERE user_id = ? ORDER BY created_at DESCが一番多かったのでindexを貼るとすごい点数が上がった。わーい。

16:36 erbをerubisに変更 23914→24951 add erubis by euglena1215 · Pull Request #20 · wantedly/shisucon2019-teppei-haruki · GitHub 定番のやつ

この辺で「もうこれ以上触ると壊れそうだし何もしない方がいいよね*2」ということで片付けて撤収した。

その後結果発表で優勝したと聞いてよかったねーとなった。

感想

今まで参加していたISUCONではインフラ周りを全く触っていなかったのでとても良い勉強になってよかった。
本番のISUCONも本選出場できるよう頑張りたいです。


延長戦

競技終了後、雑談をしているとその間に他のチームが47000点を叩き出していて悔しかったのでもう少し頑張ることにした。

最終的に65000点で終了した

*1:本来はSHISUCONではこの問題を使う予定だったけど自分が解いていることを知って急遽SHISUCON2日前に問題変更したらしい。ごめんなさい

*2:と言いつつも競技終了5分前に「とはいえSELECT *くらいは消せるのでは?」と修正してしまいエラーがめちゃくちゃ出て死ぬかと思った。触っちゃダメ絶対

心理的安全性について

バイト先の人に「うちで働く可能性ってある?可能性が低いとしたら何があれば高くなる?」という質問をされて考えたことを書きます。

人は皆「心理的安全性」の高いところで働きたい

心理的安全性を「自分がそこに所属していてもよいと思えるかどうか」と定義したとき、大きく分けて3つの心理的安全性が存在するのではないかと考えました。

  1. 精神的な心理的安全性
  2. 金銭的な心理的安全性
  3. 成長に対する心理的安全性

そして、それぞれの心理的安全性に対する係数を自分の中で持っていて、係数を掛け合わせた3つの和を各企業で比較して「どこで働くか」を決定しているのではないかと考えました。

a + b + c = 1; 0 ≦ a,b,c ≦ 1

働きたさ = a * 精神的な(ry + b * 金銭的な(ry + c * 成長に対する(ry

式で表すとこんな感じです。

精神的な心理的安全性

本来の意味での心理的安全性です。 「精神的な」と「心理的」は意味が重複している気もしましたが、明確に分けて使いたかったのでこのように表現しました。

基準として挙げるなら

  • チーム内で安心して発言できるか
  • チームにおいて自身が必要な存在だと思えるか

とかだと思います。

精神的な心理的安全性を見極める方法は

くらいしか思いつかないです。

しかし、残り2つの心理的安全性と比べチームで大きく上下する気がします。
入社するまで部署が決定しないような大きめの会社だとギャンブルですね、、、

金銭的な心理的安全性

ざっくりと言えば「お金がいっぱい・安定してもらえるかどうか」です。いくら精神的に肯定されているとしても求める生活水準に達していないと働き続けるのは難しいですよね。

会社が潰れにくいかどうかもこの安全性に入るのではないでしょうか。
大きめの会社は金銭的な心理的安全性が高く、小さいベンチャーのような会社は金銭的な心理的安全性が低い傾向にあると言えます。

基準として挙げるなら

  • 満足した水準の生活が送れるか
  • 突然辞めさせられてもXヶ月無職で生きていける程度の貯蓄が可能か
  • そもそも辞めさせられる可能性が高いかどうか

とかだと思います。

金銭的な心理的安全性を見極める方法は

  • 提示された年収を見る
  • 会社の業績をチェックする
  • 働いている人のTwitterとかをチェックして生活レベルを把握する*1

くらいだと思います。

成長に対する心理的安全性

ざっくり言うと「自身の市場価値が上げやすい環境か」、もっと言うと「何も考えなくても自然と市場価値が上がっていく環境か」です。

精神的な心理的安全性は「自分がそこ(そのチーム/企業)に所属してもよいと思えるか」だとすると、成長に対する心理的安全性は「自分がそこ(その業界)に所属してもよいと思えるか」に対応すると考えています。

もちろん、何も考えなくても自然と市場価値が上がっていく環境に属しているから自身は何も努力しなくていい、という話ではないです。
毎日5時間勉強するのが当たり前の高校に通っている人と毎日カラオケ・ゲーセンで遊び呆けているのが当たり前の高校に通っている人*2を大学受験の入試難易度という物差しで比較すると有意な差は存在するよね、という話です。

そもそも学び続ける必要があるのかという議論があると思いますが、自分の所属するIT業界の中のWebサービス開発の分野においては「学び続ける必要がある」と考えています。
理由は、利用している技術の代謝が早いため、今主流となっている技術が1,2年後も主流であるとは限らないからです。 この辺りは散々議論されてるのでここでは割愛します。

成長に対する心理的安全性を見極める方法は

  • 技術発信をしている
  • 技術的に難しいとされる領域に取り組んでいる
  • 勉強会の会場になっている
  • 強い人がたくさんいる

とかになると思います。

 


 

人生のフェーズによってどの心理的安全性を重視したいかは変わってくるだろうし*3、会社によってもどの心理的安全性を重視しているかは違うと思います。*4

なので、現時点での自分の志向性に合った心理的安全性を重視している会社を選ぶのが良さそうです。

*1:一応書いておくと自分はこれやったことないです

*2:それはそれで楽しそう

*3:所帯を持つと「一定ラインの金銭的な心理的安全性は必須」とかなりそう

*4:働きやすさを推す会社もあるし、高給を推す会社もあるし、圧倒的成長を推す会社もある

引っ越し備忘録

筑波大学に3年次編入してからもうすぐ2年になります。 卒業に必要な単位は取得し、卒業論文も提出し、あとは卒業研究の発表と細々した課題を出せばOKという状態になりました。

ありがたいことに就職先も決まっています。
オフィスは都内なのでつくばからは通えません。(ぜっっっっったい通いたくない)
なので引っ越し先を探して引っ越すことにしました。

ちなみに情報科学類に3年次編入した同期で院進せずに就職したのは自分だけなはず。
なぜ院進せずに2年で卒業する判断をしたのかはまた今度書きます(多分)。

2年前に編入でつくばに来た時に引っ越しを経験したはずなのに全然覚えてなかったため、忘備録としてまとめておくことにします。

いつ・どうやって物件を探すか

まず悩んだのが「いつ・どうやって物件を探すか」でした。
これは自分なりの答えを持っていて、それは「ちょい遅めに不動産屋さんに行く」です。

「ちょい遅め」とは4月入社の場合、1月第2週くらいを指します。 成人の日前後辺りでしょうか。

Q. なぜちょい遅めなのか

Ans. たくさんの候補の中から探すのが面倒だから。

自分は物件の条件の下限が高専の寮になってしまっていました。
そのため、ほとんどの物件はパスし「まあ住めないことはないよなあ」と全然絞れませんでした。
なので他の人がある程度選んだ状態から物件決めようと考えました。

加えて、都内の物件だと契約後2,3週間以内から家賃が発生するケースが多く、住んでいないのに家賃を払うのはもったいないな、という気持ちもありました。

Q. なぜ不動産屋さんなのか

Ans. いい感じにチョイスして提案してくれるから。

これに尽きます。web上のだと迷ってしまうので。

物件の検索条件をどうするか

先ほど述べた通り、ほとんど物件に対する必須の条件がありませんでした。

強いて挙げるなら

  • オフィスから1.5km圏内(社の住宅補助の範囲)
  • 1Kで7畳以上
  • コンビニかスーパーがそれなりに近い
  • 自転車の置けるスペースが欲しい
  • 家にお風呂がついていてほしい

くらいだと思います。 住宅補助圏内以外の条件は無理なら無理でまあ対応できるかなと考えてました。

結果どうやって決めたかと言うと、不動産屋さんが提案してくれたものの中からなんとなく良い気がする物件を選択しました。

次引っ越すときはもっと主体的に決めようと思います。

初期費用で全財産溶ける

初期費用は家賃の4~5ヶ月分だから早めに貯金しておこうね、という話です。

初期費用は敷金、礼金、仲介手数料、初月家賃、保険、鍵交換代などによって構成されています。 敷金・礼金がそれぞれ1ヶ月分、初月家賃はもちろん1ヶ月分、仲介手数料1ヶ月分、保険・鍵交換代その他諸々合わせて1ヶ月分、合計して5ヶ月分という感じでしょうか。

ざっと計算すると

家賃 8万 → 初期費用 32~40万
家賃 10万 → 初期費用 40~50万
家賃 12万 → 初期費用 48~60万

くらいになるかと思います。

都内のイケイケIT企業のオフィスへ自転車通勤できる物件となると1K7畳で10万前後するのは普通みたいです。

つくばの家賃は3~4万くらいで初期費用もそれほどだったというのもあり、あまり準備してなかったので全財産が溶けました。

引っ越しタイミングでバロンチェアを買う計画を立てていたのですが、一瞬で消滅しました。

引っ越し運送費は時期によって値段めっちゃ変動する

サカイ引っ越しセンターは実際に家まで来てくれて荷物の量から見積もりを出してくれます。
自分は何もしなくていいのでありがたい。 ついでにお米2kgくれました。

で、見積もり結果は

  • つくば〜東京
  • 3月上旬
  • 家具一式+段ボール20箱分(よくある一人暮らし分程度)
  • 荷造りと荷解きは自分で行う

で8万ちょいでした。
荷造りと荷解きもやってもらうプランにすると+3,4万くらいになるとのこと。
5~10万くらいなのかなと思っていたので想定内です。

見積もりに来てくれた人に話を聞くと

  • ヤマト運輸が引っ越し事業から撤退したせいでまじヤバイ。
  • もし引っ越し時期が3月下旬だったら3,4倍の見積もり金額を提示してる。
  • 3月下旬に北海道〜東京、一人暮らしサイズで100万近い額を提示したことがある。客からの怒られが発生した。が、他の引っ越し業者は見積もりを出すことさえできなかったので客は100万近い額で引っ越しを行った。

など色々面白い話が聞けました。

なぜ繁忙期はそこまで値段が跳ね上がるのかという質問をしたところ、
「自社で持っている運送能力を超える量の注文を受けると運送能力を外注して注文を遂行する、という仕組みになっている。外注はオークションのような仕組みになっていて、競合他社と文字通り競り合った金額分引っ越し費用に上乗せされてしまう」
との回答が得られました。 なるほど。

運送能力の入札の最適化とトラックへの積み込みの最適化(1つの大きなトラックに複数人分の荷物を載せることがある)の2つを同時に解いているらしく、なかなか面白そうな領域だなと思いました。

ライフライン・住民票といった事務処理

電気

1週間以上前の申し込みであればインターネット申し込みができる。
最悪前日でも電話すればいける。 立会いの必要なし。

オール電化のところに引っ越す場合、料金プランの関係で契約当日はお湯が沸かせないので注意が必要。

ガス

立会いの予約さえ取れれば前日でもいける。 立会いの必要あり。

水道

前日でもいける。 立会いの必要なし。

役所関係

転出・転入の申請ができるのは平日だけなので適当なタイミングで行く。

住所変更

各種サービスで入力している住所を変更する。

多分色々と忘れているものがあるので引っ越し先への郵便の転送サービスの申請した。


 

次に引っ越すときは東京の波に揉まれて調子乗った物件の条件を提示してたりするのでしょうか。
自分の成長が楽しみです。

プログラミング以外の趣味を探した話

年末なのでポエムを書いてみようと思った。

プログラミングという趣味は一般社会に対してウケが悪く、属性が異なる初対面の人との話題に超困ったので他の趣味を探してみたよ、という話。
「プログラミングが趣味で何が悪い、ウケを気にして趣味を探すことがそもそも間違っている」といった議論をする気はない、と一言添えておきます。

プログラマは趣味もプログラミングの人が多いと感じる。 プログラミングと言ってもコードを書くことだけがプログラミングではなくネット記事・雑誌を読む、知人との議論による情報収集もプログラミングに含まれると考えている。

このサービスを作るとしたらどんな技術選択をするか、最近よく聞く言語/ライブラリを触ってみてどう感じたか、サービスを作る上でどんなことを大事にしているのかといった議論をするのは最高に楽しい。

自分もプログラミング以外の趣味はなく、「あなたの趣味/好きなことは何ですか?」と誰に聞かれると「コードを書いてなにか物を作ることです!」と答えていた。

もちろん世界中の人が「プログラミング」という趣味を面白がってくれるわけではないということは理解していたが、通っていた高専という学校の属性上あまり気にすることはなかった。*1

 

プログラミングという趣味は一般社会においてウケが悪い *2と気付いたのは知り合いがやっている居酒屋で定期的に行われているパーティに参加したときだった。

パーティでの会話
初対面の人「休みの日とかって何してるの?」
ぼく「コード書いたり技術系の記事読んだりすることが大半な気がします」
初対面の人「へー!すごい、ずっと勉強してるんだ」
初対面の人「そういうのじゃなくてどこか行ったりとか普通に遊んだりとかってしないの?」
ぼく「プログラミング以外?うーん、あんまりないですね...」

書いていると趣味関係なく自分が単純にコミュ障なだけではという気がしてきた。

どうやら「プログラミングは勉強だから遊びの内に入らない」と考えている人たちがいるらしい。 大学へ編入するため広島から関東へ拠点を移し色々な人と会うようになると、そのように捉える人たちに会う回数は増えていった。

高校へ行き大学へ進学した人たちが当たり前のように持っている「初対面の人と共通の話題を探しつつ会話を膨らませる能力」に対する強い憧れを抱くようになった。

「エンジニア属性を持たない人との共通の話題がなくて話が盛り上がらない」

この現状に危機感を感じた自分はプログラミング以外の趣味を探すことにした。

読書

とはいえどうやって探せばいいのか分からなかったため、小説を読み登場人物の趣味を参考にするという方法を考案し実践した。 (元々本を読むのは苦ではなかったというのも大きいのかもしれない)

しかし読んでいるうちに目的を忘れ単純に読書を楽しんでしまっていた。 が、読書は現在も継続できているので結果オーライ

最近はpaperwhiteを購入したため読書が加速している。

ダーツ

前からダーツが少し気になっていたので少し真面目にやってみようとマイダーツを買い、家の近くにあるダーツができる漫画喫茶に定期的に行くようにしてみた。

  • 肘のxyz座標を変化させない
  • 投げる時の手の軌道と肘が同一面上にあるか
  • リリースのタイミング

この3つのパラメータを調整し最適解を探索する計算機になった気分でやっていた。
自身をチューニングする感覚が新鮮で楽しかった、

ただ、だんだんと同じことの繰り返しに感じるようになり足が遠のいていった。 ある日ダーツをしている間は耳と頭が暇なことを発見したのでダーツしながらTech系Podcastを聞いたところ、体験がとても良かったのでなんとかまだ継続できている。

1,2時間くらい投げてると1,2本HAT TRICKが出るくらいになった。

美術館

「美術館行ってみない?」と友達に誘われたのがきっかけで美術館に行くようになった。それまでは美術館は行っても面白くないと思っていたが、一度予習して美術館に臨むと面白いことに気付いた。

漠然と作品を見て綺麗・荒々しいといった感想を持つのではなく、 作者が何を感じながら生き死んだのかを追体験するためのマイルストーンとしての作品、そう考えながら見ていると面白いと感じるようになった。

おそらく鑑賞する対象が作品から作者へ移ったからだと思う、
1人で行くときは音声ガイドを必ず借りる

 


 

現段階では読書・ダーツ・美術館が定番になっている。見返すとインドア且つソロで楽しめる内容に偏っていることに気付いた。まあいいだろう、突然アウトドアの趣味を探しても継続できないことは目に見えている。

もちろん定着しなかった趣味も存在する。

 

ウケが悪くない趣味を見つけるという本来の目的を達成したかどうかを確かめるには「初対面の人と話す」という検証フェーズが行う必要があるが、それは自分にとって多大なエネルギーを必要とするため現時点では実行に移せていない。

消費エネルギーが少なく、それなりのサンプル数を得るための効率的な方法としてはマッチングアプリがいいのかなあと思案している。同性のサンプルは得られないので別の方法も考える必要がありそうだけど。

 

そんな感じで2018年お疲れさまでした。来年もよろしくお願いします。

*1:高専在学中は「4学科もあるんだしそれなりに多様性あるよね」と思っていたが、卒業してから偏りがあったことに気付いた

*2:この記事で"ウケが悪い"とはそのネタを元に会話を膨らませる難易度が高いことを指す

Slackにアップしたスライドをいい感じに見れるやつ作った

これは呉高専 Advent Calendar 2018の23日目の記事です。

先日、kosen12sというコミュニティで発表した内容をつらつらと書いていきます。
スライドはこちら ↓

speakerdeck.com

なぜ作ったのか

自分が所属している研究室では毎週交代で最近読んだ論文をスライドにまとめて発表し合うイベントがあります。
とても良いイベントなのですが、現状として作ったスライドが共有されず「他の人が作ったスライドを見返せない」「自分が紹介するときに紹介済みの論文を載せていないか心配」という問題がありました。

以下のような脳内議論が行われた結果、、、


案1 : Slackにアップロードするよう声かけをすればよさそう?

Pros

  • Slackは研究室でよく使ってるのでアップロードは楽で良い

Cons

  • スライドを見返すのに使うのは難しい、整頓されていてほしい
  • スライドアップ時にキーワードも同時にpostすれば検索できるかもしれないけどSlackの検索のUXあんまり良くない(個人的感想)
  • 無料枠で使っているのでファイル容量を超えると古いファイルは削除されてしまう

案2 : speaker deck, slideshareにアップするよう声かけすればよさそう?

Pros

  • スライドが見やすく、検索しやすい
  • publicに公開するので自分のポートフォリオページとして活用できる

Cons

  • そこまで真面目にスライドを作り込んでないので心理的ハードルが高い
  • ページ開いてわざわざアップロードするのは面倒

 

Slackの特定のチャンネルにスライドをアップロードしたらシュッとweb上で公開されるランニングコスト0のツールがあればいいのでは?と思ったので作りました。

作ったもの

webページ(サンプル) → https://teppei-slides.netlify.com/

主な機能

  • アップロードしたスライドが一覧できる
  • スライドがキーワード検索できる
    • Slackでアップしたpdfのスレッドに書き込んでもらうことによりキーワードを設定
  • ユーザーのアイコンをクリックするとユーザーごとのスライドが見られる

リポジトリ

github.com

github.com

ざっくりとバックエンド、フロントエンドはこんな感じのツールで構成されています。

f:id:euglena1215:20181223154729p:plain

バックエンド

  1. GASがSlackの特定のチャンネルに新しいスライドがアップされていないか定期的に見に行く
  2. 新しいスライドがアップされていた場合、Google Driveにスライドを保存し直してスライド情報をスプレッドシートに保存する
    (Driveに保存し直しているのはSlackのファイル容量対策)
  3. GASがシートの内容をAPIとして公開する

フロントエンド

  1. GatsbyJSを使ってReactでページを作り、↑で作成したAPIを叩いて情報を取得し静的サイトを生成する
  2. netlifyを使ってwebページをホスティング

これら一連のフローで使っているツールは全て無料です。ほんといい時代ですよね。

GAS, GatsbyJS, netlifyなどのツールの説明はここでは割愛します。 スライドではめちゃくちゃ雑に紹介してるので初耳な人は↑のスライドを見てみてください。

がんばったところ

PDFの表紙画像の取得

表示画像の取得はスライド共有ツールを作るときに悩む問題で、この記事だとpdftocairoを使っています。

今回は無料の範囲という制約があるためGASで完結できるよう色々調べていると、 Slackはpdfをアップロードすると表紙の画像も取得できることを発見しました。

f:id:euglena1215:20181223191210p:plain

今回はこの機能を利用して表紙画像を取得しました。

余談ですが、Slackは画像をアップロードすると数種類のリサイズした画像も返してくれます。Slackは画像のリサイズ用SaaSとしてとても優秀です。

react-pdf-js で日本語が表示されない

PDF.jsをReactで使いやすくするためにwrapしてくれているreact-pdf-jsを使ってスライドの表示をしていたのですが、日本語が表示されないという致命的問題がありました。

原因としてはフォント情報が入っているcmapファイルのpathがPDF.jsにちゃんと届いてないという、PDF.jsを使った開発をしているときによく発生するあるある問題でした。

github.com

なのでreact-pdf-jsにPRを投げて修正しました。

研究室での普及活動

いくら頑張ってツールを作っても、作りっぱなしだと普及しないのは今までの経験から分かっていることなので

  • 使い方スライドを作ってアップロードする
  • 論文紹介の担当者にアップロードしてもらえるようDMで根回しをする

といった普及活動をしています。

まだ論文紹介の担当が1周していないのでもう少し普及活動は続けていく必要があるかなと思ってます。

 


 

こんな感じのツールがランニングコスト0&だいたい3日間くらいでできたのでほんといい時代だなと思いましたまる。

RailsのCookieStoreをnodeで復号する

背景

既に動いているRailsアプリケーションとfrontendの間にBFF用のnodeサーバを立てて、認証情報(currentUserIdの取得)はBFFで吸収させたい。

※ Session管理にCookie Storeを使っているRailsアプリケーションを想定しています。

書いた

RubyMarshal.loadRuby独自の機構なのでnode-marshalを利用した。

環境変数Railsアプリケーションで使っているSECRET_KEY_BASEを設定する必要がある。
expressのmiddlewareとして書いたので使うときは下のような感じになる。

import cookieParser from "cookie-parser";
import express from "express";

const COOKIE_NAME = "_sample_app_session_development"

// middleware
const app = express();
app.use(cookieParser()).use(setDecryptCookies(COOKIE_NAME));

参考にしました

encryption - How to decrypt a Rails 5 session cookie manually? - Stack Overflow
rails-cookie-parser/index.js at master · instore/rails-cookie-parser · GitHub

ISUCON8で予選敗退してきました

昨日、ISUCON8のオンライン予選があり予選敗退してきたのでその様子を報告します。

牛久大仏「う〜ん、顔採用w!」 というチーム名で筑波に編入した同期の@k5342, @chigichan24とISUCON8オンライン予選に参加してきました。

↓↓チームメンバーの記事はこちら↓↓

k5342.hatenablog.com

chigichan24.hatenablog.com

Rubyで参加しBest Scoreは5000点、最終Scoreは4000点と学生枠ボーダーには全然届かない点数でフィニッシュしました。

サーバはserver1: DB, server2: app1, server3: app2として利用し、
app1にベンチに来てもらい、ラウンドロビンでapp1とapp2にロードバランシングするといった構成になっていました。

スコアが目に見えて上がったのは複数台構成に変更したときくらいでした。

github.com

もちろんやってないこともたくさんあったけど、それなりに高得点者の歩いていた道を辿っていた気がするのでもう少し点数伸びてもよかったなぁというのが正直な感想です。


以下詳細です。

また、自分が関係するムーブだけ書いていきます(他のメンバーのムーブはブログに書いてくれるはず)

時刻 作業内容
前日
16:00 Redisの使い方をブログにまとめる→ これ
22:00 1台構成→複数台構成時に変えたときに起こりうる問題を色々考える
今まで1台構成でばかり解いていたので色々考えることがあることが分かって、色々調べた
当日
8:00
10:05 DBのschemaを確認する
10:30 自分のポートでwebサーバを立ち上げようとするが失敗する、ここで時間を多少消費する(firewalld周り)
11:30 reservationsのreserved_atにindexを貼ってみる
11:45 kataribe, myprofierを入れる(nginxに置き換え作業が発生していたため待ち時間が発生する)
←DBめちゃ重との連絡を受けたのでN+1を潰していくことにした
15:00 get_eventsから呼ばれてるget_eventのみ修正しN*N+1をN+1に改善した #6 
サクッと書いたクエリを「ほんまに合っとんかこれ?」と3人で悩む時間が発生していた(合っていた)。ここでかなりのタイムロスをした感がある
15:20 get_eventsのtransaction要らなくね?となったので外した #7
16:30 get_eventをN+1→1にした #8
クエリ自体は1になったけど処理方法がよくなかった(Array#selectでぐるぐる回しまくっていた)
17:00 開発に使っていたサーバからの移動を命じられ、いそいそと移動する
17:15 app serverのメモリがやべえという連絡を受け、メモリを節約できそうな場所を探すがよくわからん(残り1時間を切っていたのでget_eventを複数回呼んでいるところの修正は諦めた)
17:30 メモリ使用を減らすためにとりあえずSELECT *を消した、が終了直前だったのでマージは見送られた #10
17:45 app serverの再起動確認を行った&ベンチにenqueueされる様子を眺めていた
17:55 やることがなくなったので反省会開始
ISUCON終了
18:30 同じ場所でISUCONに参加していたluvtechno(カニオムライス), qnighy(カニオムライス), Altech(カニオムライス), gedorinku(winjisucon)と一緒に反省会会場(焼肉)へ移動
f:id:euglena1215:20180917115632j:plain:w450
↑反省し終わった(肉を撮り忘れていた)
Wantedly社員の人が反省会費用を出してくれた(特にCTO)!ありがとうございます!
22:30 つくばへ帰り反省会2次会(ラーメン)へ移動
ISUCON第2ラウンド開始
23:45 色々とやってないことはあったのでおもむろにPRを作り始める
f:id:euglena1215:20180917115924p:plain:w500
24:00 get_eventsでpublicなイベントだけ欲しい場合も一度全てのイベントを取得してからフィルタリングしていたのでSQLで行うように変更 #11
24:30 get_eventの修正後の処理がよくなかったので最適化した #12
25:20 get_eventをループ内で複数回呼んでるところ用にget_events_from_idsを作った、これが動けばN+1は全滅のはず #13
26:00 メモリが足りないとのことだったので不必要な変数の取り回しをなくした #14

おまけ

また、今回は自分のインターン先のWantedlyオフィスを会場として使わせてもらいました。

f:id:euglena1215:20180917123610j:plain

チームメンバーのうち1人は元インターン生、1人はWantedly全然関係ないという状況でしたが快諾してもらってありがとうございました!

f:id:euglena1215:20180917124431p:plain

所感

  • 初動が遅かった
    コードを書き始めたのが13:00ごろだった、このころには1万点弱に到達していたチームもちらほらいた気がする
  • 例年よりも作り込まれていてすごいと感じた
    フロントエンドはvue.jsで書かれていて時代の波を感じた
  • p debugよりもbinding.pryの方がやはり優秀
  • 帰ってからlocalで開発してみた結果、明らかにlocalで開発した方が実装速度が早いことが判明した(vim難しい)
  • 来年からは社会人として出るのでもっと力をつけていきたい