Diary of a Perpetual Student

Perpetual Student: A person who remains at university far beyond the normal period

株式会社はてなに入社しました(本物)

株式会社はてなに入社しました

株式会社はてなに入社しました - hitode909の日記


といういつものやつではなくて、これは本当の入社エントリ(にしては遅すぎないか?)です。

株式会社はてなにWebアプリケーションエンジニアとして入社して4か月が経とうとしています。 はじめての査定結果が通知され会計年度が終わろうとしているこのタイミングで振り返っていきます。

自己紹介

id:arthur-1 です。お理工だけじゃダメなんだ大学の学部に7年間通った後に、はてなに新卒入社しました。 3留なのでどこにも雇ってもらえないと思っていたけどなんとかなりました。

学生時代は学園祭実行委員会で参加団体向けの Web 申請システムやお客さん向けの優良企画投票システムを作ったり、ボードゲームに関する Web サービスを個人開発・運用したりしていました。

db.buratsuki.page

neo.buratsuki.page

また、専攻はコンピュータサイエンスだったのですが、研究では比較的得意だったプログラミング系から距離を置き、数理最適化×信号処理という分野をターゲットとしていました。

会社のこと

新卒研修

新卒エンジニア研修として、他の新卒エンジニアと一緒にとある社内向けサービスを開発しました。 この時の話だけで 1 エントリ書けてしまうので、今回は触れないでおきます。

技術グループのPodcast である Backyard Hatena でも少しだけ紹介されています。

developer.hatenastaff.com

所属チームのこと

5日間のエンジニア研修が終わったのちに、Mackerel という監視 SaaS の開発チームに配属されました。

ja.mackerel.io

Mackerel 開発チームへの onboarding

「Mackerel アプリケーションエンジニア入門」として、各領域に設定された実績を解除していきました。 チームとしてのタスク(スプリントバックログアイテムの消化)をメインとしてこなしつつ、余った時間で以下のような内容について学習しました。

幸いなことに、Mackerel で使っている技術スタックと自分が持っていたスキルがある程度合致していた(Scala・TypeScript+React)ので、業務に必要なプログラミングの習得には時間がかかりませんでした。 join して 3日目には最初の Pull Request をマージすることができました。 しかし、インフラ周り(特にクラウドサービス)の知識はほとんどなかったため、最初は話についていくのが大変でした。

メンターを始めとするチームメンバーの方々から絶妙なタイミングで新しいことにチャレンジする声掛けをしていただきました。 そのおかげで、毎日少しずつ背伸びをしながら、できる業務の幅を少しずつ広げていくことができました。

また、SRE と同じチームで一緒に仕事をしていることもあり、入社時と比べて格段にインフラ周りの知識が身についています。 これは、留学するとめちゃくちゃ英語できるようになる、みたいな話と近いかもしれません。

業務の上で心がけたこと

dogfooding

Mackerel を自分で使っているうちに見つけた要改善ポイントを、積極的にプロダクトバックログアイテムとして起票しています。 誰のどんな課題をどうやって解決するのかをきちんと言語化するのは大変ですが、時間をかけても良い大事な作業だと考えています。 これによってプロダクトオーナーを始めとするチームメンバーに、課題そのものや、課題の価値によってプロダクトの価値を上げられるということを共有することができます。 結果、優先度が高いと判断されたアイテムは、素早くスプリントに載せられ、チームとして取り組むことになります。

大規模なシステム開発だと、上から降ってきたタスクをただこなしているだけの人間になってしまいそうと思っていましたが、現実はそうではありませんでした。 Mackerel チームのスクラム開発では、 dogfooding を通じて明らかになった課題を、プロダクトの価値を高めるために解決していく仕組みが整っています。 自分がプロダクトに貢献できているという実感を持って取り組む仕事はとても楽しいです。

また、dogfooding から始めたこの取り組みによって、他のプロダクトバックログアイテムについても、利用者のことを考えた進め方を提案して進めることができています。

先ずテストより始めよ

チームに join してしばらくの間は、アプリケーションの仕様の理解に時間が掛かります。 先にテストを書いたり修正したりして、不安な場合にはこの状態で他のエンジニアに見てもらうことで、仕様への理解を深めました。 その上で、テストが通るようにアプリケーションコードを改修しました。

闇雲にタスクに取り組むのではなくテストコードから始めることにより、手戻りを減らしつつ、自信を持って Pull Request を作ることができました。

最後に

特に入社エントリとしてのまとめとしての話は用意していないのですが、このエントリで楽しく仕事をしていますという雰囲気が伝われば、エントリの目的は果たしていそうです。

これだけだと締まらないので、将来の話を少しだけします。

8月から始まる来半期は、自分の成長だけを考えていた状態からチーム・プロダクトの成長も合わせて考えられるようにシフトしていきたいと考えています。 チームとしてカバレッジが足りていない領域や、プロダクトが抱えている問題に合わせて、自分の成長の指針となる目標を設定しようと、メンターやディレクターと相談しています。

こんな形で今後も public な振り返りを定期的に書いていきたいですね。

ISUCON 12: はじめての ISUCON 体験記

ISUCON 12 予選にチーム「横浜の缶詰」*1として参戦し、最終スコア 9368 点を残して敗退しました。参考値ではありますが 104 位(661 チーム中?)ですね。

isucon.net

結果としては残念な感じですが、初めての ISUCON で今後の成長に繋がるやり方を貫き通せたところが良かったと思っています。次回以降も前向きにチャレンジしていきます。

さて、事前準備や当日の様子・学びについて振り返っていきます。

事前準備

まず、3人で作戦会議をしました。アプリケーション担当 2人 + インフラ担当 1人という形で分担することにしました。(自分はアプリ担当。)

また、事前演習として、チームで ISUCON 10 予選問題を解きました。計測すると明らかに「なぞって検索」が支配的に重いことが分かるのですが、ここの改善は MySQL の GEOMETRY 型(初見)が登場してとても難しいです。なんとか改修することができたのですが、演習時間のほとんどをこれ1本に注いで終わってしまいました。

演習後、チームで KPT 法による振り返りを行いました。以下はその抜粋です。

  • K: deploy 周りのスクリプト用意されていてよかった
  • K: log の grep テク大事
  • K: 計測して改善のムーブを大事にできた
  • P: 今何をしているか共有できなかった
  • P: 重いタスクを2つに分割したつもりだったけど完全に分割できていなかった。2人で同じところにハマってしまった
    • T: リソース効率よりもフロー効率を重視して、基本ペアプロで進めていく

加えて、チームでの事前演習とは別に社内の ISUCON 練習会に参加しました。朝まで飲んでいたら寝坊したので、本番前日はたとえ飲みに行っても終電で帰るという強い誓いを立てました。

予選当日

このセクションでは、アプリケーション担当の id:arthur-1 目線で競技中のタイムラインを記述する。(インフラ担当の頑張りはあまり記述していない。)

9:30 起床

起床チャレンジ成功。ゴミ捨てチャレンジには失敗した。

10:00 マニュアル・ドキュメント読み合わせ開始

インフラ担当が準備している間にアプリ担当2人でマニュアルを読んだりブラウザで動作確認したりしていた。

10:30 リポジトリ準備完了

インフラ担当がソースコードGitHubリポジトリとして共有した。ソースコードをまじまじと眺めて、テナントごと SQLite のファイルがあるのに気づき戦慄する。

動画で CSV によるスコア入稿が重いという話があったので、 func competitionScoreHandler を読んでいた。明らかに n+1 なので、bulk insert にしたり一括で select するようにしたい。

11:00 対戦環境が整う

Discord に alp や slow-query の結果を投稿してくれる君が動くようになった。alp の結果を正規化し、ベンチを回して解析結果を眺めようやくスタートラインに立つ。

GET /api/player/competition/:competition_id/ranking エンドポイントを 2人がかりで改善していくことに決定。

11:30 competitionRankingHandler をターゲットに

visit_history という謎テーブルはどうやら課金額の計算に使用しているらしいことが分かる。以下の修正方針を立てる。

  • player_score テーブルに index 張りたい
  • retrievePlayer を for文で回しているところが n+1 なので直したい

改善したいクエリって slow_query に載ってるのか?という痛い指摘を受けたけれど、残念ながら SQLite なので改善すべきクエリなのかはわからない。

11:50 player_score に index 張った

他のクエリに影響がでないよう player_score 関連のクエリを洗い出して index 設計。SQLite だと CREATE TABLE と同時に INDEX 作れないことを知る。

12:20 デプロイ成功 & index の効果をベンチで確認

自分達で build したバイナリのデプロイ成功。スコアは誤差レベルでほとんど変わっていない。

12:40 SQLite 脱却の決意

GET /api/player/competition/:competition_id/ranking の n+1 クエリ脱却に成功。デプロイしたが、スコアは向上せず、むしろ下がってしまった。pprof や alp の結果を見ると明らかに良くなっているのだけれど。

これは SQLite なのが悪いと断定した。また、以下の点から出題者が MySQL への移行を推奨しているのではないかと思った。

  • テナントごと DB が分かれているにもかかわらず、tenant_id カラムが用意されていること
  • SQLite の db ファイルを SQL のクエリ列に変換するスクリプトが用意されていること

SQLite のままだと3台フルに生かした複数台構成にしにくいこともあり、脱却を決意した。

13:50 アプリケーションコードの SQLite 脱却完了

昼休みを交互に取りながら、SQLite 脱却作業を行う。

tenantDB にアクセスしに行っているコードを adminDB に書き換える作業が完了した。残すは初期データの生成のみ。

14:10 tenantDB の初期データを MySQL に作り替え始める

tenantDB 初期データの mysql 向けの dump ファイルを作りたい。sqlite3-to-sql スクリプトの出力結果を MySQL に食わせているけど永遠に終わる気配がない。これはでかい釣り針に釣られてしまったのではないかと焦り始める。

15:15 bulk insert に変換する

sqlite3-to-sql スクリプトの出力結果を bulk insert に変換するスクリプトができたので、初期データを MySQL に移すのを試してみる。

max_allowed_packet に邪魔されて実行できない。

15:30 MySQL 移行諦める

事前練習でなぞって検索に全振りしてしまった反省から、 MySQL 移管を損切りすることに決める。

これができないと App 2+ DB 1 のような複数台構成を目指すのがかなり無理になってしまい、インフラ担当が今後できる改善ポイントが減ってしまうので、やり遂げる技術力がなくてただただ残念に思っていた。

作戦会議をして、全体としては GET /api/organizer/billing の改善に pivot することに決めた。

また、僕は動画で紹介されていた CSV 周りの処理が気になっていたので、 POST /api/organizer/competition/:competition_id/score の改善に取り組むことにした。

15:50 competitionScoreHandler の n+1 を直す

POST /api/organizer/competition/:competition_id/score の処理が n+1 になっていたので直した。元から NamedExecContext を使っていたので bulk insert に書き換えるのが簡単だった。優しさを感じる。

この頃インフラ担当が App + DB の 2台構成を試していたのでスコアの比較はできなかったが、少しは改善しているように見えた。

16:45 billingHandler の改善を進める

visit_history を記録しているけど、課金に必要なのは最初の visit の情報だけなので、 min_visited_at を記録するテーブルとして分割することにした。コードの改修が終わってベンチを回すも整合性チェックに fail する。

どうやら、初期化時にテーブルの生成ができていないようだ。webapp/sql/admin/10_schema.sql に書けば良いと思っていたけど、このファイルはアプリケーションでは使っていないことに気づく。init.sql に移し替える。

16:55 最高スコア記録

インフラ担当の頑張りによって、最高スコア 9777 点を記録する。確か player_id の謎の生成方法をやめて uuid に変えていた。

17:05 min_visited_at 初期データ作り

500 エラーは発生しなくなったが、引き続き整合性チェックに引っかかる。そもそも、初期から visit_history にレコードがあるので、ここから初期データの min_visited_at を作らなければならないことに気づく。

ここを直すと大幅にスコアが伸びると期待されていたので、焦りながらも黙々と進める。

17:30 初期データ作り失敗

min_visited_at の初期データを作るクエリを組み立てるのに試行錯誤していた。成功するも整合性チェックに通らず。どうやら課金額 50 円ほど少なく計算されてしまっているようだ。課金計算という言葉に拒否感を覚え始める。

インフラ担当が店じまい(デバッグログ出力の停止など)を始める。

18:00 競技終了

最終スコアは 9368 点。結局 GET /api/organizer/billing の改善を完遂することはできなかった。最後のデバッグログ停止などはあまりスコアに響かなかったようだ。

チームで振り返りをした後解散。夕食を食べて酒を買い出しに行き、社内のオンライン反省会に参加した。PHP 大好き〜〜と語っていた。

スコアの変遷

感想

個人的には、以下の点について反省しています。

仕様の理解をおろそかにしていて、改善アイデアが参照実装コードに縛られていた

コードがユーザにどんな機能を提供しているのかの理解をおろそかにしていました。コードを見れば、「あっ、ここは n+1 なので直せるな」といったことはすぐに分かります。しかし、このような一目でわかる小手先の改善だけでは戦っていけません。その関数が結果として何を返しているかをあまり考えずにいたので、「visit_history テーブルってそもそも必要なくない?」などの抜本的な改善のアイデアに辿りつくことができませんでした。

ブラウザ上でアプリケーションを動かすのをもっと丁寧にやると良いのかもしれません。

コーディング速度が遅かった

単純に、改善ポイントを見つけてから改善するまでの時間をもっと短くしたいと思いました。チームでは Go 言語を選択したのですが、僕は Go を読み書きし始めて日が浅く、流暢にプログラムを書くことができませんでした。

ISUCON に関する圧倒的な情報量・pprof などの使いやすい解析ツールの有無を考えると、Go 言語を選ばないとハンディキャップになってしまいます。仕事でも Go 言語を使う機会がかなりあるので、半年以内には素早く書ける言語にしていきたいです。

とは言ったものの、最初の練習から比べるとかなり書けるようになったので、その分は自分を褒めたいです。NamedExecContext を見て「おっ!」と反応するのは golang 初見ではできなかったでしょう。

最後に

ISUCON めちゃくちゃ楽しい!!!本当に isuports(esports) そのものだと思いました。ISUCON に取り組むことで得た技術力やマネジメント力はきっと業務に活かせると確信しています。来年も絶対出るぞ!!!!

*1:チーム名は ISUCON チーム名ジェネレータ で決めました。たまたま自分は横浜市民でした

最近聴いてる曲: Jul. 2022

社内でおすすめの新譜を載せていくチャンネルが生えていてめちゃくちゃ良いな〜と思った。

全然新譜ではないけれど最近聞いてる曲を淡々と載せていく。

我愛你 / Cody・Lee(李)

www.youtube.com

ドラを鳴らす曲を作りたかったので参考に。

ただ選択があった / フロクロ

www.youtube.com

IV△7→♭VII7 が最高。

24 night / matsudamiki

www.youtube.com

近所のラーメン屋さんでずっとこのアーティストの曲を流しているので聴いている。*1

負け犬 / RuLu

www.youtube.com

缶缶さんめちゃくちゃカッコ良い〜〜〜良い。アルバムとしても結構好きな曲が多いので良く聴いている。

唇の凍傷 / ワルキューレ

www.youtube.com

華やかな転調、そして転調。

君たちキウイ・パパイア・マンゴーだね。 / 古幡愛

www.youtube.com

名曲のカバー。みんな言ってるけど PV が良い。

まるで霧雨のような / はるふり

www.youtube.com

ギターの音色、シンセソロ、好きな要素しかない。

感想

仕事始めてから高校の軽音部に定期的に遊びに行くことがなくなってしまったので、若者のトレンドについて行けていない感じがする。

*1:と思ったけど、この前行った時には Just the Two of Us が流れていて、あれ?ってなった

悪しき日にレジリエンスを考える

この4月にブログを新しく作り直したのですが、前のブログの記事の移転がまだできていません。

それはそうと、今日は自分が昔書いたエントリを掘り返して、令和最新版にリファインメントしていこうと思います。

東日本大震災

急に思い出した話を書きます。

7年弱前*1に起きた東日本大震災。 (もうこんなに昔なんですね)

当時僕は中学2年生で、学校の体育館で3年生を送る会を行っていました。 突然の長い揺れ。ガラスの割れる音。

急いで教室に戻りテレビをつけると、大津波警報の文字が。 震源から数百km離れた沼津でも、保護者引き渡しとなりました。 家に帰るための国道は津波警報のため通行止めになりました。

中学の体育館は、新しいものができるまで立ち入り禁止になりました。 仙台の親戚の家は水たまりを残して跡形もなくなりました。 電池などの物資が不足し、大阪の友人が送ってくれました。

震災から1週間経ったある日、 国語の授業のはじめに先生がこんなことを言いました。

「大震災の報道を見て、 非日常に興奮してしまっている自分がいるんじゃないか。 みんなも自問自答してみてほしい。」

この発言は非常に衝撃的でした。 さして当事者でもない僕の気持ちを表現するに どれほど的を射た発言だったでしょうか。

多くの人が亡くなって、 生き残った人も過酷な避難生活を過ごして、 大規模な原発事故も起きて、

そんな状況に自分は興奮しているとするならば、 どれだけ残酷なことだろう、 と子どもながらショックを受けました。

こんなことをメディアで言ったら それこそ津波のような勢いで叩かれるでしょう。 しかしながら、それを的確な言葉で伝えた先生。 この立場だからこそできることだと思います。

不謹慎という言葉だけで片付けられるでしょうか。

ニュースや週刊誌に載っているのは他人の不幸ばかり。

これは人間の真理なのかもしれません。

最後の締めにそれっぽいことを言っていますが、結局何が言いたいのか分からない文章ですね。これは、当時の自分が「じゃあ人々はどうしたら良いのか」という問いに対する回答を明確に持ち合わせていなかったことによります。書いた当人(自分です)は満足しているかもしれませんが、これではただのポエムです。

4年半経った今、自分の思っていることを、解像度を上げて書いていきます。

客観視し、自分を受け入れる(抽象)

僕は医者や心理学者ではないので断定はできませんが、大きなインパクトのある事故や事件に対して、落ち着きのなさを感じるのは心理的反応としておおむね自然なものでしょう。無理して「いつも通りに生きよう」という気持ちにはなれない、もしなれたつもりでも本当にそうなのかは分からないと思います。

レジリエンスという言葉があります。心理学の分野では、自己に不利な状況に自身のライフタスクを対応させる能力を指すそうです。

ja.wikipedia.org

アメリカ心理学会が提唱する「レジリエンスを築く10の方法」のうちに、「変えられない状況を受容する」ことがあります。動揺し興奮した自分を否定せず、生理的現象・事実として許容することが、レジリエンスの面で有効ではないかと考えています。

仕事の話に例える(具体)

Web アプリケーションエンジニアをしていると、多かれ少なかれシステム障害に遭遇することがあります。対応中、当然多くのエンジニアは焦燥感を覚えるでしょう。焦った結果、ミスコミュニケーションが発生したり、判断ミスでより良くない結果をもたらしたり、ストレスを感じ engagement の低下に繋がったりすることになります。

しかし、「焦らないようにしよう」「落ち着いて対応しよう」という TRY が提示されても、それを実現するのは難しいと思います。もちろん、こういった問題への対応は、個人の努力だけに依存せず、仕組みで解決する方向に持っていきたいですね。ただ、理論的にはそうでも、個人の心情問題なので難しいところがあります。

1つの策として、事象を受け入れられない自分や他者を客観視し、受け入れるという方法があるのではないかと思います。これは個人的な経験に基づくものでしかないのですが、自分の感情を一歩外から引いて見つめ、「まあそういうこともあるよね」「人間として自然だね」と事実として受け止めることで、感情の保持者という意識が薄れ落ち着くことができます。「落ち着け」と言って押さえ込むのは、ポジティブフィードバック*2になる可能性があり、制御の観点上望ましくありません。外圧を受け入れしなやかに適応していこうとすることが、無理せず維持できる、あるべき心の持ちようなのではないでしょうか。

最後に

いつかこの話をしようとずっと思っていたのですが、自分の身の回りのあらゆる様子が乱れている今日この頃に、言葉としてまとめておきたかったのでした。そして、この行動自体もまた防衛機制の表れなのかもしれません。

*1:本エントリ執筆は2017年12月20日です

*2:前向きな内容を相手に伝えるという意味ではありません: ポジティブフィードバック - Wikipedia

LambdaでSlack Botを開発するTips

本エントリは、バックエンドにAWS Lambdaを用いたSlack Botを開発するときのTipsを雑多に垂れ流していくものです。普段の記事と異なり、エントリとしての主張のまとまりに関してはほとんど考慮していません。

Slackで使えるインタフェースを把握しよう

Slack Appを作るとき、我々はSlackの仕様に縛られることになります。Slack側が用意してくれているインタフェースを使ってユーザはAppとやりとりすることになります。

ただ、Slack Appでは思ったよりもリッチなアプリケーションを作れます。作りたいものが決まって余裕があるなら、Slackが提供しているユーザインタフェースのうちどれを使うと良い体験になるかを考えてみると良いでしょう。(そもそも、こんなUIが実現できるんだという存在を認識するところがスタートです。)

  • メッセージ
  • スラッシュコマンド
  • モーダル(アクション)
  • ホームタブ
  • ショートカット
  • ワークフロー

もちろん、UIがリッチになっていくほど実装は大変になります。作り始めから特定のUIに依存しない形でサービスロジックのコーディングができていると、他のUI経由にしたいときも実装を変えやすいです。

Slack Appの設定はコード化しておこう

複数人で開発すると、どうしてもSlack Appの設定(エンドポイントURLや必要な権限など)の情報を各人で共有することが難しくなります。開発環境と本番環境など、同じような設定を複数のSlack Appにしたいならば尚更です。

インフラ構成をIaC (Infrastructure as Code) で管理したくなるのと同様に、Slack Appの設定はmanifestファイルとして管理することができます。

api.slack.com

個人でお遊びのものを作る分には良いのですが、業務で使うようなAppの開発は引き継ぎできるかも大事なポイントの1つです。設定をコード化して属人化を防ぎましょう

レスポンスは3秒以内にSlackに届けよう

スラッシュコマンド実行時やModalでの送信時に、SlackからSlack Appに対してリクエストが送られます。API Gateway経由で起動したLambdaでそのリクエストを処理してレスポンスをSlack側に返してあげる必要があります。

ここで、リクエスト送信からレスポンス到着までの時間が3秒以上かかってしまうと、Slack上では「何らかのエラーが発生しました」と表示されてしまいます。ある程度時間がかかってもレスポンスさえ返せばSlack上での画面変化が正常に行われるのですが、エラーと表示されてしまうとユーザとしては不安ですよね。

アルゴリズムの改善や実行に必要なファイル群のサイズを減らすなどによって実行時間を減らすことができますが、これらの細かい工夫だけで解決ができるかは保証できません。何より、他のAPIにアクセスして結果をもらうという典型的な処理においては、そのアクセスのレイテンシも乗っかってくるので、自分たちがいくら努力しようともどうしようもないことがあるでしょう。

以下の記事で紹介されている通り、レスポンスを受け取ったらすぐに空の200を返してしまい、その後で黙々と処理をするのが良さそうです。

qiita.com

また、金銭的余裕があるなら、Lambdaのコールドスタートをできる限り回避するためにプロビジョニング済み同時実行を使うなどの工夫も考えられます。(それだとLambdaの良さ台無しでは?というところではありますが。)

なお、Slack Appレベルの規模の場合、ランタイムの選択によって3秒問題を解決できるほど大きく実行時間が変わるということはないと考えています。JavaScriptでもGoでも好きな言語を選ぶと良さそうです。(ただしJavaは微妙かも。)

acro-engineer.hatenablog.com

dev.classmethod.jp

Slackの再送による多重実行を回避しよう

「レスポンスは3秒以内にSlackに届けよう」にも関連するのですが、SlackがSlack Appのエンドポイントにリクエストを送った結果エラーとなった場合、Slackは自動でリクエストを再送します。これは、3秒以内にレスポンスが届かなかったとき(http_timeout)にも起こるので、上の問題と絡み合って不具合の原因特定と解消が困難になってしまいがちです。

Slackのお節介な仕様が必要でなければ、再送された場合のリクエストに対しては処理せず200を返すだけにしてしまいましょう。概ね、以下の記事の「パターン3, そもそも再送を無視する方法」に紹介されている通り、ヘッダを見て再送しているリクエストかどうかを判別するのが良さそうです。

dev.classmethod.jp

AppからSlackにメッセージを投稿する場合、エラーハンドリングの方針を考えよう

Slackを通じて何らかのアクションを行う場合、きっとSlackのメッセージで結果を返したくなるでしょう。もし、バックエンドのメインロジックの処理が成功したのに、その後でSlackのエラーが発生してレスポンスがエラーになると、一見処理は正しくできているのにSlack上では「エラーが発生しました」と表示されてしまいます。

で、Slackのエラー(もっと具体的に言うと、LambdaからSlackのAPIを叩くときのクライアントエラー)なんて起こるのかというと、意外と起こる可能性があります。例えば、SlackのAPIは短い時間でたくさん呼ぶとthrottlingエラーを返します。1回のアクションに対して複数回postするような場合には注意が必要です。

補助的にSlackのメッセージを送りたいのであれば、あえて、Slackの投稿に失敗してもLambdaの実行失敗としないようにエラーを隠してしまうのも一つの手だと思います。

逆にSlackにメッセージを送るのがMustな要件の場合は、キューサービス(AWS SQSなど)を挟んで投稿専用Lambdaを作るとよいでしょう。投稿用Lambdaは投稿に失敗したら異常終了するようにし、Queueに再送することでthrottlingなどによる投稿失敗を防ぐことができます。何回も失敗する場合には何かがおかしいので、Dead Letter Queueに入れて元のキューが詰まらないようにし、DLQのメッセージ数をモニタリングしてアラートを出すと良さそうです。

リンク集

標準エラー出力が見れなくなるpreztoユーザはバージョンを確認しよう

結論

  • 昔のpreztoを使っている人は、最新のリポジトリの状態を反映しよう

本文

僕のターミナルがおかしい

僕のターミナル環境はなにかがおかしい。何がおかしいかというと、標準エラー出力に書き込まれているものが見えなくなることがありました。

コマンドの実行に失敗しても結果が見れず何も表示されないため、「あれ?一瞬でコマンド終了したけど成功はしてないな?ステータスコードも0じゃないし……」と困惑していました。

経験的にCtrl+cを押した後に確率的に動かなくなるという感覚を持っていました。また、新しいタブを開くとそのタブでは問題が解消することも知っていました。

この現象が、OSを問わず、僕の使っているあらゆるPCで発生していて、とても気持ち悪いなと思っていました。

preztoが悪いのだろう

そんな生活を2年ほど続けていたのですが、さすがに嫌になってきたので、原因調査と問題解消に取り組むことにしました。

実は原因はzshの設定にあるのだろうということは大方分かっていました。Macのデフォルトシェルがzshになって、preztoを導入した頃からこの事象が発生し続けているからです。

pretzoとはzshフレームワークのようなもので、様々なプロンプトのテーマを選んだり、補完や情報表示ができるプラグインをかんたんに導入できたりするものです。好きな僕はprezto本家のリポジトリをフォークして自前のcustomを施したものを各PCでcloneして使っています。

github.com

こんなデザインのターミナルに見覚えがありませんか?

ただ、「prezto 標準エラー出力 見れない」などと検索してもそれっぽい情報にたどり着くことができず、甘んじて受け入れていたのです。

issue発見

今日は本気で調べようと思ったので、英語で「pretzo stderr」と検索したら、あっさりと同様の不具合を訴えるissueが見つかりました。

github.com

依存していた zsh-async で、stderrを/dev/nullにマップしたままにしてしまうバグがあったようで、現在は改修されているとのことです。

そういえば、最初にforkしてから一回も本家リポジトリの最新版をpullしていないなあということに気づきました。

問題解決

2, 3年分の変更をpullして、自前のカスタムとのコンフリクトを解消しつつpreztoを最新版に置き換えることができました。

$ cd ~/.zpretzo
$ git stash
$ git pull git@github.com:sorin-ionescu/prezto.git master
$ ## コンフリクト解消
$ git commit
$ git push origin master
$ git stash pop
$ ## コンフリクト解消
$ git restore --staged
$ git stash destroy

*1

何度かコマンド実行中にCtrl-cを押して確認していますが、標準エラー出力が見えなくなる事象は発生していないような気がします。

まとめ

一度整備した開発環境を弄るのは、壊れてしまう可能性もあるので躊躇われますよね。ただ、ソフトウェアが意味もなくアップデートすることはそれほど多くありません。今回はシェルの設定に問題がありましたが、開発環境を構成する様々な要素の更新履歴を定期的に確認し、暇な時間にアップデートする習慣をつけていきます。

*1:余談ですが、git checkoutがgit switchとgit restoreに分かれていたことを最近知りました。たしかにcheckoutでできることが広すぎましたね

自宅にYAMAHAの業務用ルータを導入してみた

こんにちは、ネットワーク初心者のid:arthur-1です。今回は家のネットワーク環境整備の話をします。

学生時代には学園祭実行委員会の1ロールとしてITインフラ管理をやっていました。「ネット繋がらない!」「プリンター調子悪い!」という声に24時間体制で対応できるよう、学園祭期間中おもてなしせずに死んだ顔で部室にいたのも今は昔。それも、別に専門的な知識があってやっていたというわけではなく、マスタリングTCP/IPの入門編は一通り読んだなあという程度のものです。

今回のお話をまとめると、概ね以下の内容になります。

  • ASUSのルータもIPoEに対応したと思っていたけど完全ではなかった
  • 仕方ないので調子に乗ってYAMAHAのRTX830を買った
  • せっかくなのでVPN構築した

環境

  • ぷらら光 ホームタイプ
    • フレッツ 光ネクスト ファミリー・ギガラインタイプ 相当
    • ひかり電話未契約のため、ルータ機能がないONUを借りている

ASUSのルータが好きだった

実家にいたころは弟の希望でASUSの無線ルータを使っていたのですが、管理画面がモダンな感じでけっこう気に入っていました。

一人暮らししても同じようなインタフェースで触りたいと思い、以下の無線ルータを購入しました。

ASUSのルータはv6プラスに対応していたけど…

実家ではPPPoEしか使えない時代遅れのプロバイダを利用していたのですが、一人暮らしの家ではIPoE (IPv4 over IPv6)で繋いで爆速にしたいと考えていました。なぜIPoEにしたら嬉しいかという話は他のサイトに詳しいです。

www.ntt.com

一応自分の言葉でも説明してみます。

  • 従来のPPPoE接続よりIPoE接続のほうが高速
  • ただし、IPoE接続はIPv6前提で、これだけだとIPv6対応サイト(割りと少ない)しか見られなくなる
  • IPv4 over IPv6という技術を組み合わせると、IPv4の通信もIPv6経由で行うことができ、全てのサイトを高速に閲覧できる

先程紹介したASUSのルータも、ファームウェアアップデートにより「v6プラス」に対応したという情報を手に入れていたので購入したものになります。So-netのWebサイトにはv6プラスについての説明が以下の通り掲載されています。

「v6プラス」とは何ですか?

「IPoE接続方式によるIPv6インターネット接続」と「IPv6ネットワーク上で実現するIPv4インターネット接続 (IPv4 over IPv6) 」を指します。 IPv6通信だけでなく、IPv4通信もIPoE接続方式で利用できるため、さらに快適にインターネットをご利用いただけるようになります。

www.so-net.ne.jp

僕はこの説明を読んで、v6プラス対応のルータを買えば、IPoE経由でIPv4のサイトを閲覧できると思いました。ところが、実際にセットアップしてみると、なぜか繋がらないのです。

この理由は、IPoE×IPv4 over IPv6を実現する接続方式が1種類ではなく複数種類あり、「v6プラス」はそのうちの1種類だったからです。ブランディングのために名前を変えているというわけではなく、方式として異なるものということです。

  • v6プラス
  • IPv6オプション
  • transix (DS-Lite)
  • IPv6高速ハイブリッド IPv6 IPoE + IPv4
  • OCNバーチャルコネクト
  • クロスパス

そして、僕が利用しているぷららでは、v6プラスではなくOCNバーチャルコネクト方式を基本的に採用しているとのことでした。「ぷららv6エクスプレス」というサービス名だったので名前から採用方式まで知ることはできないのもあって、原因調査は困難を極めました。

ASUSルータはOCNバーチャルコネクトには対応していないので、この製品を大元のルータにしてしまうと、IPoEの恩恵に預かることができません。海外製品だから仕方ないですが、仕様乱立し過ぎだろ、とも思います。

業務用ルータに手を出す

仕方ないので(?)業務用ルータメーカとして名高いYAMAHAのRTX830を購入しました。正直NECAtermとか無難に国内メーカの家庭用ルータを買えば解決する話ではあったんですが、会社のネットワーク強そうな先輩方から勧められたので良い機会だと思って購入しました。

network.yamaha.com

もちろんこれだけだとWi-Fi接続ができないので、購入したASUSのRT-AX3000はアクセスポイントモードにして接続しました。二重ルータにするのは管理が面倒だし家庭用途で選択するメリットは薄いですね。もちろんホームゲートウェイ利用者などが何も知らずに自然と二重ルータにしてしまう例は数多くあるとは思いますが。

設定は大変かな~と思っていたのですが簡単でした。IPoEで繋げたいな~という顔をしてWebコンソールでポチポチしていると気づいたら設定が終わっています。もちろんOCNバーチャルコネクトにも対応しています。

VPN構築

これだけだと業務用ルータにしたうま味が少ないので、外出先から家のPCにリモートデスクトップ接続できるよう、VPNの設定をしてみました。

もちろん家庭用回線だし固定IPアドレスはもらっていません。しかし、DDNSというものを使うといつでも同じ名前で自分の家のネットワークにアクセスすることができます。グローバルIPアドレスが変わったときにルータがDNSサーバに通知してレコードを変えてくれるものです。YAMAHAのルータにはネットボランチDNSサービスというものが付随しています。

network.yamaha.com

(ちなみにDDNSサービスはASUSのルータにもついていました。)

設定手順は以下の通りです。

  • OCNバーチャルコネクトだけではなく、サブとしてPPPoEによる接続設定も追加
  • PPのインタフェースに対してDDNSを設定
  • VPNの通信はPPPoE側に流すようフィルタを設定

これらを全部説明してもよいのですが、長くなってしまうので各自他のWebサイトの情報をあたってください。業務用ルータはコマンドで設定しなきゃいけないというハードルを感じる人もいるかもしれませんが心配いりません。今回の設定はすべてWebコンソールから行えました

まとめ

  • IPoE × IPv4 over IPv6 を使うとネットが速くなりがち
  • でも、接続方式が複数あるのでプロバイダ採用の方式を調べてからルータを選ぼう
  • DDNSサービス使うと固定IPなくてもVPN運用やりやすい

以上で爆速インターネットとVPNを手に入れたのでした。(完)

(これでも大学の専用回線には遠く及ばないので光クロス対応エリアになってほしい。)