SEAN_BLOG

プログラミング etc.

Git worktree × tmux で Coding Agent を並列実行するワークフロー

ここ数年、自分でコードを書く時間が明らかに減った。代わりに Claude Code や Codex といった Coding Agent に指示を出し、コードを書いてもらうことが増えてきた。 コーディングを自分で行っていた頃は、設計・実装そのものに脳内リソースと体力を注ぐ必要があった。 しかし今は、各 Coding Agent に指示を出し、その後は待ち時間が発生することが増えたように思える。自分の役割が、変わってきたように思う。

EM 的な開発

たとえば Todo list アプリを開発していて、次のタスクが積まれているとしよう。

  1. 各アイテムの削除機能
  2. 各アイテムの詳細追加機能
  3. バックグラウンドの色を黒から白に変更する

以前なら、自分自身が設計・コーディングを行うため、1 → 2 → 3 の順で逐次実行するしかなかった。 しかし Coding Agent を使えば、Agent A にタスク 1 を、Agent B にタスク 2 を、Agent C にタスク 3 を同時に依頼できる。まるで複数のエンジニアにタスクを振るエンジニアリングマネージャーのように振る舞える。

ところが、すぐに問題にぶつかった。

壁 1:コードの競合

複数の Agent を同一コードベースで並列に動かすと、それぞれの変更が互いに競合してしまう。結果として、結局は逐次実行せざるを得なかった。

worktree による解決

調べてみると、git worktree でこの問題を解決できることがわかった。worktree を使えば、同一リポジトリから複数の作業ディレクトリを独立して切り出せる。 ブランチを別ディレクトリとして同時にチェックアウトできる、git の機能である。 実はこのアプローチ、Claude Code を作った Boris Cherny さんも「Single biggest productivity unlock」として推奨している。チームの多くが worktree を好んで使っており、Claude Code にネイティブサポートが追加されたのもそれが理由だという。

これにより、各 Agent を独立した worktree 上で動かすことが可能になった。先ほどの Todo list の例で言えば、タスク 1・2・3 をそれぞれ待たずに同時実行できる。

壁 2:pane hell

自分はターミナルのセッション管理に tmux を使っている。そこで、プロジェクトごとに window を作り、worktree ごとに pane を分けて開発を進めることにした。 プロジェクト数が少なく、worktree も 1〜2 本程度なら、この方法で十分だった。

しかし現実はそうではない。2〜3 のプロジェクトを並行しながら、各プロジェクトで最大 5 つの worktree を立てていると、あっという間に "pane hell" に陥った。どこにどの worktree があるのか、まったく把握できない状態だ。どの Agent がどのタスクをやっているのかも分からない。

window 単位の管理

そこで、worktree ごとに window を作る方法に切り替えた。 ただ、これも辛かった。worktree の作成・Claude Code の起動・シェル用 pane の追加・ソースコード確認用 pane の追加*1。これらをセットで毎回手動でやるのは、地味に骨が折れた。

kage(影)

こうした経緯から、worktree を window 単位で手軽に操作できるツールを作成した。 影分身を操るように、各 Coding Agent をコントロールするイメージ。

github.com

tmux と git worktree を使って、複数の Coding Agent セッションを管理する CLI ツール。

影分身の術のように、各 Agent が独立した worktree・tmux window 上で並列に動く。TUI ダッシュボードから作成・切り替え・削除を一つのキーで操作できる。 Agent は問わず、Claude Code・Codex など、CLI ベースのツールであれば利用できる。

具体的には、新しい feature branch を作ると次のことが自動で行われる。

  • 指定リポジトリに git worktree を作成
  • tmux window を開き、設定に従って pane を分割
  • 各 pane で Agent やシェルを起動

あとは TUI ダッシュボードから window を切り替えるだけで、それぞれの Agent の状況を確認できる。削除時も、worktree と tmux window がまとめて消える。

kage demo

終わりに

正直いまだに自分もいかに自分がボトルネックにならないように開発を進めるか模索中。 もし、より良いプラクティスがあれば教えて欲しい。

*1:自分はエディターに vim を利用している。

カナダ - 2025/26: CPTPP - T52 ワークパーミット申請

CPTPP - T52 (Professionals) を利用しワークパーミットを取得した。自分が申請を進める中であまり情報を見かけることがなかったので、各種手続きの内容を記載しておく。

対象読者

  • 来年以降の自分*1
  • CPTPP - T52 (Professionals) (以下、T52)でワークパーミットの取得を検討している人

CPTPP - Professionals and technicians (T52) とは?

横文字が多くよくわかりにくいが、CPTPP とは簡単に言うと日本やカナダを含む 12 カ国が参加する貿易協定。 その一環で加盟国同士の取り決めの中で特定の条件を満たす管理職や専門職の人材に対して発行されるワークパーミットの申請カテゴリー。

一般的にカナダでワークパーミットを取得する場合、LMIA (Labour Market Impact Assessment) という手続きが必要で、雇用主が当該のポジションでカナダ人労働者を雇うことができないことを証明する必要がある。 このプロセスは時間がかかる上、とても煩雑なため雇用主、申請者双方にとって負担が大きい。

有難いことに日本もこの協定に批准している。そのため、T52 を用いてワークパーミットを取得することで金銭的・時間的なコストを大きく抑制することができる。

個人での申請について

現在の勤務先はそこまで規模も大きくなくお抱えの移民コンサルタントは不在。 それどころか自分がサポートを依頼した時点では、前例は一件もないとのことだった。

ただ、幸運なことにサポートに対してはとても前向きで、やることがわかれば進めてくれるとのことだった。

移民コンサルタントの方に代理申請を依頼し丸投げするのも一つの手段であった。 数社相見積もりをとると $3,000 前後かかるとのことだった。

少し申請方法に関して調べてみると、書類集め・作成の工程が煩雑なだけで、あとは必要な書類をアップロードするだけでそこまで難しくなさそうなことが判明した。 自分は永住権申請に関して時間決めのコンサルをすでに依頼していた。この枠内であれば T52 に関しても、質問対応が可能とのことだったので、都度質問しながら自分で申請を進めることに決めた。

一応、自分は過去にシンガポール(ワーホリ)、カナダ(ワーホリ、RO ワーホリ)を自分で申請したことがある。そのため、他の人に比べればこういった申請作業に対しての抵抗が少なかった。

金銭的に余裕があり、手続きが心配な方は移民コンサルタントの方に依頼するのが安心安全ではあると思う。

時系列

申請(申請者側)からトータルで、115 日ほどでワークパーミットを取得。公式のページには 250 日程度かかるとの記載があったので、半分ほどで取得が完了した。

2025/09/15

雇用主側の申請完了。 通称 A ナンバーと言われるコードを人事担当者から貰う。このコードは申請者側の提出フォーム該当項目に入力する必要がある。

2025/11/04

申請者側の申請完了。 IRCC のポータルサイトから必要書類をアップロードする。 必要書類の取り寄せ、作成など、段取りの悪さが露呈し、雇用主側の申請完了日から 1 ヶ月ほど時間が空いてしまった。

2025/11/05

申請完了の翌日 WP-EXT only except PGWP と呼ばれる書類が送られてくる。 これはいわゆる Maintained Status を証明する書類で、申請の日から最長 1 年、ビザの申請結果が決定されるまで現状保持するビザの条件のもと働くことを許可する旨が書いてある。

2025/12/24

Submission Confirmation と呼ばれる、申請受理を通知するメッセージが送られてくる。 これは結果とは関係がなく、受理したのでこれから処理を始めますという内容が記載されている。

2026/03/04

Correspondence Letter が送られてくる。 ビザが承認されたこと、ビザ本体は所定の住所に後日郵送されることなどが記載されている。

2026/03/11

自宅のポストにワークパーミットの原本が配送される。

申請手続きと必要書類

IRCC のアカウントにログインし、Apply to come to Canada から申請を行う。 いくつか自分のステータスに関する質問をされるので、それらに回答すると必要書類をアップロードする画面に遷移する。 恐らく、表示される項目は個々人のステータスによって異なる。

Application Form(s)

Application to Change Conditions, Extend my Stay or Remain in Canada as a Worker (IMM 5710) (required)

所定のフォームに必要項目を入力する。内容は氏名や生年月日などの基本情報、学歴、職歴など。 このフォームに雇用主から共有された A ナンバーと呼ばれるコードを記載する。 フォームの編集に際して Adobe Acrobat を利用しなければいけないのが難点。

Supporting documents

Offer of Employment (required)

現職入社時に発行されたオファーレター。 相談していた移民コンサルタントの方には最新の日付で再発行してもらった方が良いとのアドバイスを貰っていた。 ただ、人事担当者と話す中でオファーレターを再発行することはできないと言われたので、入社時に発行された過去の日付が記載されたものを提出した。

Passport (required)

写真のページ、スタンプが押されているページをスキャンして提出した。

Invitation Letter (required)

You must provide a letter of invitation from the person inviting you to Canada.

移民コンサルタントの方に伺ったところ基本的には不要とのこと。 ただ、この項目は必須となっており、ファイルをアップロードするまで先に進めないので Offer of Employment を再度添付した。

Digital photo (required)

証明写真。会社の近くのキオスクでとってもらったものの電子データを提出した。

Proof that you meet the requirements of the job being offered (required)

下記の書類を一つの PDF にしたものをアップロードした。

  • 学位記
    • 最終学歴である修士(科学)。元々記載が英語であるため、翻訳は不要。
  • 職歴詳細
    • 提出するフォームに記載欄があるがスペースが限られている。自分が提出する Certificate of Employment の発行主がこの欄に記載できなかったため、箇条書き形式で過去全ての職歴について期間、タイトル、雇用主、場所を記載したものを作成。
  • Certificate of Employment
    • 必要条件のうちの職歴を証明するもの。新卒でお世話になった会社に 4 年弱在籍していたので、その会社に依頼して作成してもらった。
    • 本人(氏名、生年月日)、雇用主(名前、住所、電話番号、HP URL)、職務内容(タイトル、雇用形態、雇用期間、給与・賞与等、職務内容)、日付、に社判、人事担当者サインをもらったもの。
  • 源泉徴収票・原本
    • 上記 Certificate of Employment を発行してもらった企業の在籍期間分の源泉徴収票。手元になかったので、当該の企業に依頼して再度発行してもらった。
  • 源泉徴収票・英語翻訳
    • 取り寄せた源泉徴収票を Certified Translator に依頼、翻訳してもらったもの。
    • KAN Communications Inc. さんに依頼し、5 枚トータルで $280 ほど。

Client Information (required)

昨年度分の T4、および、直近 2 ヶ月分の Pay stub を提出した。

Optional documents

この項目は未提出。

Fees

$155 を支払う。あまり記憶に残ってないが恐らくカードで支払いをした。


本記事は筆者自身の申請経験をもとに作成したものです。 ワークパーミットの申請手続きは、個人の状況(ビザステータス、職歴、学歴、雇用主の状況など)によって必要書類や手順が異なる場合があります。本記事の内容はあくまで一例であり、すべての申請者に該当するものではありません。 また、移民法および関連する規則は改正されることがあり、本記事の情報が最新の状況を反映していない可能性があります。申請にあたっては、必ず IRCC 公式サイト および認定移民コンサルタント(RCIC)や弁護士にご確認ください。 本記事の内容を参考にしたことによって生じたいかなる損害・不利益についても、筆者は一切の責任を負いかねます。


*1:該当のワークパーミットの有効期間は 1 年の為、永住権の取得が間に合わなければ再度取得する必要がある。

カナダワーホリ - 2025: OHIP 申請

2025-02 に The Ontario Health Insurance Plan (OHIP) を申請したので、その際の手続きを記載しておく。

対象読者

ワーキングホリデー(以下、ワーホリ) でカナダに滞在中に、オンタリオ州の州保険の申請を行う予定の人。

TL;DR

  • ワーホリでも一定の条件を満たせば OHIP に加入可能
  • 申請に必要な書類は下記
    • Form: Registration for Ontario Health Coverage
    • Proof of Canadian citizenship or OHIP-eligible immigration status
      • Work permit
      • Employment letter
    • Proof of residency in Ontario
      • クレジットカードの Statement など
    • Proof of identity
      • パスポート  

申請条件

申請に必要な条件は下記公式サイトに記載あり。

Apply for OHIP and get a health card - Who qualifies

ワーホリ滞在者の場合、主に下記の条件が関係すると思う。

  • be physically in Ontario for 153 days in any 12‑month period
  • are in Ontario on a valid work permit and are working full-time in Ontario, for an Ontario employer, for at least 6 months

上記の条件を考慮すると基本的には、滞在半年程度で申請することになると思われる。 自分の場合は、2024-02 からワーホリで、その後 RO ワーホリに切り替えて滞在しているので特に問題はなかった。

必要書類

Registration for Ontario Health Coverage

こちら からダウンロード可能。 個人情報などを記入する。

Proof of Canadian citizenship or OHIP-eligible immigration status

  • Work permit
  • Employment letter

一週間ほど前に同僚が OHIP を申請しており、Offer letter だとダメという旨を聞いていたので、HR に依頼して Employment letter を発行してもらった。 記載内容は、名前、雇用開始日、雇用条件(Full-time permanent)、ロール、雇用者情報。

正直、見た感じでは似たり寄ったりなので、なぜ Offer letter だとダメなのかは不明。

申請時にカウンターで「この仕事は Hybrid なのか?」、「どのくらいの頻度で出社するのか?」、「オフィスはどこにあるのか?」等の質問を受けた。

Proof of residency in Ontario

  • クレジットカードの Statement

事前に Phone bill を過去 6 ヶ月分プリントアウトして持って行った。 ただ、直前に引越しをしていており住所が変わっていた為、クレジットカードの Statement で代用した。 後々聞いたところこちらは直近 1 ヶ月分で問題なく、PDF などのデータでも良いとのこと(スクリーンショットは不可)。 自分の場合も銀行のアプリで PDF を表示してそれを担当者が確認して終わった。

ただ、紙を大量に無駄にしただけだった。。。

Proof of identity

  • パスポート

申請方法

Service Ontario に直接出向いてカウンターで申請した。 自分は土曜日に開いている下記のロケーションに行った。

Yonge and Davenport (Toronto)
Located in: Canadian Tire
839 Yonge Street
Toronto, Ontario M4W 2H2

https://www.ontario.ca/locations/serviceontario/yonge-and-davenport-toronto

予約はせず 11:30 頃に行ったが、待ち時間は 1 時間程度だった。 受付で申請書類を提出し、口頭でいくつか質問を受けた後、写真を撮られて終了。 手続き自体は 20 分ほどで完了した。

当日は Health Card は発行されず、3 週間程度で自宅に送られてくるとのこと。 一応、仮のドキュメント(1 枚物)が発行されるので、それを持っていれば病院等での利用も可能とのこと。

カナダワーホリ×エンジニア転職 - 2024: それ本気で言ってるの?

順風満帆とまでは行かないけれど、いわゆるワーキングホリデー(以下、ワーホリ)でカナダに渡航し現在現地の企業でソフトウェアエンジニアとして働いている。 自分の周りを見渡してもワーホリ片手に現地でエンジニアとして転職を目指す人はあまり見かけない。 カナダ渡航からオファーまでの一連の流れ(2024/02 - 2024/08)を書き残して置こうと思う。

対象読者

およそ 1 年前の自分。

(聞こえますか、そこのあなたです。余裕をかまして韓国旅行を満喫している、そう、そこのあなたです。あなたの心に直接話しかけています。)

自分と似たような経歴でカナダでワーホリを利用して転職を目指す方の助けになれば良いと思う。

今までの経歴

経験としては新卒で入社した EC 系企業にて 4 年弱、その後業務委託として CRM を扱う企業にて 2 年間、 合計 6 年弱の間日本でエンジニアとしていて働いていた。

英語は一通りのことができるくらいには話すことができる。 日本生まれ日本育ちだが、学部時代に 1 年間トロントに語学留学をしていた。 また、半年ほどシンガポールでインターンシップをしていたこともあって平均に比べたらできる方ではあると思う。 昔と比べてテストの難易度が上昇しているという話も聞くのでどこまで参考になるかは不明だが、学部時代 (2016/11) に受けた TOEIC は 970 点だった。

学歴に関しては学部時代は都内の私立大学で経済学を専攻しており、いわゆる私立文系というやつ。 現在、海外の大学院にて修士(科学)をオンラインで受講している。

コーディングにも少し触れておくと、最近はあまり参加できていないものの AtCoder を少し齧っており色で言うと茶色の後半ぐらい。

カナダ渡航まで

数年前ネットでカナダで未経験からエンジニアになったという記事を見かけた記憶がある。 詳細は覚えてないが、未経験でもエンジニアになれるんだなという印象だけが残っていた。

日本、特にエンジニアとしては売り手市場なので、転職活動は容易に行うことができると思う。

自分でも LinkedIn や転職サイト経由で毎日のようにスカウトメールを貰っていた。 2 年ほど前に業務委託先を探した際もそこまで苦労することなく、数社からオファーを貰うこともできた。

そのような状況に身を置いていたこともあって、正直、

「経験もそこそこあるし、英語も人よりは話すこともできる。カナダでの転職も楽勝でしょ。」

ぐらいに考えていた。

なんならカナダに渡航する 1 ヶ月前にカナダで Data Analyst をしている友人に会った際、

「カナダのマーケットは大変だから、日本でできることはやっておいた方が良いよ。応募も日本から始めておいた方が良いよ。」

とアドバイスをもらったにも関わらず、上述の通り舐め腐ったスタンスでいたため聞く耳を持たず。 (当時に戻って、一度自分をぶん殴りたい。)

そんなこんなで 2024 年 2 月にカナダに渡航した。

この時点では一応英文のレジュメは用意していたものの、その他特にこれといって準備はしておらず、 大胆にも(今考えれば無謀ですらある)ワーホリのビザを片手にカナダに渡った。

カナダの労働市場

先にも記載の通り、日本では割と容易に仕事を見つける事ができていた。 そのため、カナダに渡航して暫くの間は、

「難しいっていっても何とかなるでしょ。」

というぐらいに考えていた。

実際はそんなに甘くはなかった。

カナダの失業率は全体で 6.8% (2024/11)、トロントでは 7.8% (2024/11) ある。日本は、2.5% (2024/10)

現地の Tech 系の Meetup に参加すると半分、または、それ以上の人が求職中だったりする。 求職中の人の方が繋がりを求めて Meetup に顔を出す率が多いということを考慮しても、求職者の多さに最初は驚いた。少なくても日本でこのような光景は見た事がない。

また、カナダであれば言ってしまえば英語を話す全ての人がライバルになり得る。 日本人であればそもそも英語という点で若干のハンデがある状態でのスタートとなる。

オファーまでの道程

到着した翌日からアプライを開始した。

しかしながら、ATS (Application Tracking System) 未対策のグラフィック重視のレジュメを使っていたこともあって、書類通過は 0 だった。

後ほどもう少し詳しく書くが、Meetup や Tech 系イベントには積極的に顔を出しており、 そこで転職情報やレジュメ、面接対策の方法に関しての情報収集を行った。

一つ一つを消化していく感じがRPG ゲームのような感覚で割と楽しかった記憶がある。

2 月中・後半あたりから ATS 対策を行ったレジュメを利用して応募を始めたこともあり、 3 月あたりからポツポツと面接に進むようになった。

その後は会社によって形式は様々だが、行動面接 、技術面接、カルチャーフィットなど複数の企業で受けては落ち、受けては落ちというループを 8 月まで続けた。 その内 3 社ほど最終ラウンドまで進むことになり、8 月に現在勤める企業からオファーを貰い転職活動を終了する運びとなった。

応募数などそれぞれの数字は下記、

*1

自分は経験とマッチするポジションに絞って応募していた。 周りの話を聞くと 2 、3 倍の数を応募している人も見かけるので、自分は比較的少ない方ではないかなと思う。

やったこと

レジュメ対策

Jobscan

ATS 対策にこちらのプラットフォームを利用した。経歴などは基本的に固定で応募ポジションごとにキーワードを調整して、応募した。 このサイトではレジュメと募集要項をアップロードするとマッチ度と言うものが表示される。 当初は 90 点を目指して色々調整を行なっていたが、70 点ほどでも通過することが判明し中盤以降は 70 点以上を目指し調整した。

その他

現地で会ったエンジニアの知人・友人数名にレビューをして貰った。 シニアのポジションなどのより高位のエンジニアであれば、自社で採用に関わることもあり採用側の立場でレビューをくれるのでとても参考になった。

SNS・ブログなど

LinkedIn

レジュメのアップデートに合わせてこちらの内容も最新の状態に更新した。 Meetup で会った採用担当者曰く、LinkedIn と GitHub は書類選考時に参考にするとのことだった。これらは出来る限り最新の状態にしておくと良いと思う。

あとは自分と似たようなテックスタックの人物に連絡をとって、アドバイスを貰おうと試みたりした。 あまり返信率は高くなかったが、返信をくれた中の 1 人とは意気投合し現在もたまにご飯に行ったりする。

その他は応募時に LinkedIn を利用した程度で、対策は特に行っていない。

少し前に、フォロワー数がどうのみたいな話題を SNS 上で見かけたが、自分はあまり気にした事がない。 ただ、昔人材系の企業でインターンをしていたこともあり、現時点 (2024/12) でコネクションの数は 2,000 人弱いる。

その他

月一ほどの頻度で英語でブログ記事を公開した。こちらは特に面接で話題に上がる事はなかったし、直接転職活動で有利に働いたということは無かった。 どちらかと言うと、定期的にブログを書くことで名前を知ってもらえる可能性は上がるので、長期的には有効なのかなとは思う。

利用した教材

InterviewCat - テック企業面接対策ガイド

行動面接の章で紹介されている質問集は事前に回答を用意して実際の面接に臨んだ。 実際の行動面接ではたまにこの質問集から外れた質問を受けることもあった。 ただ、文言が多少異なるだけで聞かれている内容は似たようなものなので一通り回答を用意しておけば対応できた。

自分はフルスタックポジションを中心に受けていたので、バックエンド・フロントエンドの両方の対策が必要であった。 こちらの教材には面接で聞かれうる想定技術質問集が記載されている。 こちらも一通り空で回答できるように準備をしていた。 実際の面接で聞かれた内容を振り返ってみると、自分の扱う言語や技術の詳細に関する質問を除いて、こちらの質問集を押さえておけば対応できた。

Grind 75

LeetCode の頻出まとめ。Easy - Medium は 2 周ほど行った。自分が受けた企業の面接では一度 Hard が出題されたが、それ以外は Easy の問題であることが多かった。 今回はいわゆる米系ビッグテックの技術面接は受けてないので、この辺りの企業がどうなのかはわからない。 自分の感覚で言えば、Easy - Medium をカバー出来ていれば問題ないと思う。Easy - Medium を優先して、時間があれば Hard の感覚で良いのではないかと思う。

Grokking the Modern System Design Interview

こちらも一通り目を通した。結果から言うと大規模アプリケーションのシステムデザインを問われることはそこまで多くなかった。 どちらかというと、一機能を作る際に、テーブル設計やロジックについて問われるケースが多かった。 こちらもいわゆる米系ビッグテックなど企業によって異なると思う。

Grokking the Low Level Design Interview Using OOD Principles

Ruby のポジションを主に受けていたので、OOP 関連の質問をよく受けた。基本的な OOP の知識や OOP を利用したアプリケーションのデザインについて。 こちらのリソースでその辺りの質問は一通りカバーすることができた。

面接対策

Pramp

模擬面接プラットフォーム。行動面接・技術面接の練習に利用した。そもそも、英語での面接自体ほとんど経験がなかったので、こちらで場数を踏んで実際の面接に望んだ。 模擬面接の相手はランダムで決まるので、面接官の質に関してはマッチする相手によって結構ばらつきがある。 中にはビッグテックで働いてるエンジニアがいたり、かたや英語もほとんど話せないと言う人ともマッチすることがあったりもした。

その他

現地で知り会ったエンジニアの友人に依頼して模擬面接に付き合って貰った。 プラットフォームなどでマッチする人よりかは近しい間柄なので、忌憚のないフィードバックを貰うことができた。

勉強会

トロントには活発なテック系の Meetup がいくつか存在する。面接などが重ならない限り、基本的に全て参加していた。 たまに勉強会などで会った人に手当たり次第にリファラルを依頼する人を見聞きするが、自分はそういう事はしていなかった。

最近はこの勉強会で会った友人たちと休日を過ごす事が多い。仲良くなった後にリファラルをして貰ったりもした。 また、現職に就く前に稼働していた契約の仕事もこの友人のうちの一人の紹介だった。

友人を見つけることもできたし、契約の仕事にもつなげる事ができたので結果を見るととても効果的であったと思う。

その他

カナダ・バンクーバーを中心に海外就職や移住、IT 関連人材の海外キャリアをサポートをしている Frog という企業がある。 自分の場合は、渡航後知人の紹介で Frog に繋いでもらった。Frog 主催のイベントごとはバンクーバーがメインなので、トロント在住の自分はあまり積極的には参加できていない。 ただ、オンラインで Visa 周りのサポートをしてもらったりしている。

無料相談や説明会などのイベントは定期的に行っているようなので、興味がある人はここから初めてみても良いのかなとも思う。

Visa 周り

2024 年 2 月からワーホリを利用して入国した。自分の場合は何も考えずに入国時にワーホリを有効化してしまった。 もし、当時に戻れるのであれば恐らくワーホリを有効化せず観光のステータスで入国しオファーを貰ってからワーホリを有効化する。 これにより、現地で働ける期間を最大限に延ばすことができる。

一般的に外国人としてカナダで働く場合、何らかの形で労働可能なワークパーミットが必要になる。 一定の条件はあるものの、我々日本人が手に入れやすいのがワーホリだと思う。 1 年間*2という限られた期間を最大限に活用するのが良いと思う。これを使ってしまうと、その後のカナダでの働けるステータスを取得する難易度が上がってしまう。

さらに言うと、現状カナダで企業のサポートを必要とするワークパーミットを申請しようとすると半年ほどの期間を要するケースもあったりする。 そうすると、ワーホリから企業サポートのワークパーミットへのスムーズな切り替えなどを考慮するとワーホリ残存期間が最低でも半年ほど無いとスクリーニングの時点で弾かれたりする。 実際に自分も米系の企業で数社、ビザの残存 6 ヶ月未満と伝えると、その時点でビザを理由にリジェクトされた。

ちなみに、自分は現在 RO ワーホリ、いわゆるセカンドワーホリというものを申請し、ワーホリの後にもう 1 年間働く資格を取得してある。*3

現在の企業からは面接時点ではビザステータスに関しては質問されず、入社後しばらく経って HR から質問された。 一応、入社時にワークパーミットの写しは提出しており、有効期間も記載してある。

現状、ワーホリと RO ワーホリで (2026/01) まで有効なビザステータスが残っているので、HR からは 2025 年に入った段階で再度話し合いの場を設けようと言われている。 一応、現在オンラインで進めている修士を取得できれば T52 と呼ばれる、一般的なワークパーミットに比べて取得難易度が低いビザも申請が可能になるのでその辺りのストリームを用いて企業側にサポートして貰うことになると思う。

PR については、自分はどうしても PR を取りたいという願望はないのだけれど、PR を持っていた方がカナダでの就職、米系テックを含めて優位に進める事ができる。 この点を考慮して将来的には可能であれば PR も取得したいと思っている。 ワークパーミットの取得と同時並行で PR の取得の方も進めていこうと思っている。 ただ、こちらは近年取得条件が難化傾向なのと移民政策の方針転換と現時点では確実ではない。 自分でできる準備は進めつつ、今後の動向を見守っていこうというスタンスでいる。

メンタル面

今の市場感だと転職するまでは長期戦となる可能性が高い。正直これは仕方がない。

さらに、渡航当時の高い自己評価となかなか結果がでないという現実との乖離。

ただ、不思議と自分は落ち込んだりメンタルがやられるということは無かった。

どこかの Meetup で会った人(A 氏)との間でこんな会話があった、

自分:「なかなか仕事見つからないんですよね。労働市場も冷え込んでて、、、」

A 氏:「それってさただの言い訳でしょ?実際この期間も仕事見つけている人はいるわけだし。」

普段あまり感情が揺れることはないのだけど、正直イラっとしてしまった。顔にも少し出てしまったと思う。(反省。)

ただ考えてみるとその通りで、それからは実際に仕事を見つけてる人と自分の間での差分を埋めることに注力した。 なので、こちらが忙しく、落ち込んでいる暇はなかったと言った方が正確かもしれない。

(正直、今でも思い出すと少しイラっとするし、絶対に友達にはなれないと思うけど、気づきを与えたくれた A 氏には感謝している。)

総括

カナダの労働市場はあまり良い状態とは言えない。自分の場合は結果的に見れば運よくワーホリで転職をする事ができた。 ただ、これは結果論でしかなく、もし確度を高めたいのであれば現地でカレッジや大学に進学し現地で働ける期間を引き延ばすという選択肢もあるのかもしれない。 *4

一旦、立ち止まってワーホリでのカナダ渡航、転職が最善の手段なのかをもう一度考えてみて欲しい。

何が最善な選択肢なのかは究極のところわからないけれど事前にこちらの市場の状況、自分が取れる選択肢を知った上で行動できると良いのかなと思う。 少なくとも、自分がカナダ渡航前に戻ったらそうすると思う。

2024 年現在、決してワーホリでエンジニア転職が不可能であるとは言わない。ただ、日本に比べてなかなか状況が厳しく、それなりの覚悟が必要である。そのことを理解した上で、事前にできる準備をした上で転職活動を有利に進めてもらいたい。

どこかの何の準備もせず浮かれ気分でワーホリ片手にカナダに渡航して半年間無職というような浮かれポンチと同じ轍を踏むことだけは避けて欲しい。

*1:上図中 R はインタビューのラウンド数を示す。企業によってラウンド数にばらつきがあり都合上 R0 - 2 にまとめたので実態と多少異なる。

*2:2025 年 4 月から最長 2 年に変更

*3:実際には letter of introduction というものを取得した状態で、国境に行って許可を貰うまで 100 % ビザを取得できる確証はない。

*4:Visa 周りは門外漢なので詳しくは専門家に聞いて欲しい。

日本の携帯電話解約後、カナダで今まで利用していた LINE アカウントを利用する方法

対象読者

日本の携帯電話を解約・カナダの携帯電話を契約したうえで LINE のアカウントの移行を試みている人。

TL;DR

  • Apple ID もしくは、Google アカウントのいずれか 1 つ以上が登録されている状況であれば、今まで通り利用できる。
  • 上記いずれかのアカウントの登録が済んでいれば、特に移行の作業は不要。

Apple ID/Google アカウントの連携 についてはこちら。

※ 上記は 2024/02 時点のもので、将来の対応方法を保証するものではない。

詳細

以下、LINE 公式サポートとのやりとり。

#1

Q.
日本の番号からカナダの番号に変更を試みています。
しかし、該当の(5)のステップにて `電話番号でログイン` が表示されず、
Apple ID でのログインしか確認できません。

現状は、日本の番号を維持しているので当面は移行せずとも問題がないと推測しますが、
将来的には日本の番号の解約を考えています。
この場合、どのようにカナダの番号に移行し、今まで日本で利用していたアカウントと紐づけることが可能でしょうか?
ご多用のところ恐縮ですが、ご確認お願いします。

https://help.line.me/line/android/categoryId/20007877/3/pc?lang=ja

A.
お問い合わせありがとうございます。
LINEカスタマーサポートです。

恐れ入りますが、現在、日本・韓国・台湾・香港・タイ以外の国・地域の電話番号への変更はできません。

お客さまのご期待にそう回答とならず心苦しいかぎりでございますが、何卒ご理解ご了承くださいますようお願い申し上げます。

なお、登録電話番号を解約された場合でも、Apple IDまたはGoogleアカウントが連携されていれば、LINEは引き続きご利用いただけますのでご安心ください。
※LINEは、電話番号/Apple ID/Googleアカウントのいずれか1つ以上が登録されている状況であれば、有効なままご利用を続けることができます
※Apple ID/Googleアカウントの連携状況は、LINEアプリ内よりご確認ください

#2

Q.
前回上記の通り回答をいただきました。

カナダの番号に紐づけることはできないとのことで理解しました。
また、Apple/Google との連携がされている状態であれば、サインインできることも承知・確認しました。

その上で一点質問なのですが、日本の電話番号のプロバイダー契約を解除したとします。
ただ、LINE のアプリ上では電話番号を空欄とすることはできないように思います。
この場合、解約した日本の電話番号が LINE 上の自分の電話番号となったままとなってしまうかと思います。
こちらは LINE を使用する上で問題はないのでしょうか?
あるいは、何らかの方法で電話番号を空欄に更新する方法があるのでしょうか?

A.
お問い合わせありがとうございます。
LINEカスタマーサポートです。

恐れ入りますが、登録した電話番号の解除方法についてはセキュリティ上の理由からご案内しておりません。
何卒ご了承ください。

お客さまが今後電話番号を解約された場合でも、LINEアカウントにApple ID/Googleアカウントのいずれかが連携されている状態であれば、LINEアカウントの利用に影響することはありませんのでご安心ください。
※Apple ID/Googleアカウントの連携状況は、LINEアプリ内よりご確認ください

平成Ruby会議01 CfP

面白そうな Advent Calendar を発見したので、せっかくなので残しておこうと思います。

adventar.org

ありがたいことに、こちらの CfP は採択されました。

厳正なる選考の結果、「Play with Ruby」の内容でSho ITO様にご登壇いただきたいです。

heiseirb.github.io

発表タイトル(※本情報は当選時にLPに掲載されます)

Play with Ruby

発表の概要(※本情報は審査にのみ利用します)

エンジニアとしての経験が1年半程の私が、 Ruby本体 への右代入の実装を通して学んだこと・気づきを発表します。

この発表を聴いた人が何を持ち帰れるか(※本情報は審査にのみ利用します)

今年の春に開催されたRubyKaigi 2019 のDay 3 に "Play with local vars" というTalk がありました。 そこではRuby 本体のlocal vars を修正するlive coding を通じて、 "Play" しながら新たなことを学習することの重要性が説かれていました。

そのTalk を聴く前まで私自身Ruby 本体を修正することは、 非常にハードルが高く難しいものだと考えておりました。 もっと言えば、C 言語の経験も全く無かった私には不可能にすら思えました。

しかし"Play with local vars" を聴講し、

"Play" しながら学習が可能であること、 Ruby 本体の修正は想像よりかは難しくないこと、

を学びました。 これにより大きく勇気付けられた気がしました。

この度のLT では私自身が"Play with local vars" を拝聴した時に得た、

実際に手を動かし楽しみ(Play)ながら学ぶことの可能性、 Ruby 本体の修正は想像よりかは難しくないこと、

この2点を参加者の皆さんに共有したいと思います。

私がRubyKaigi 2019 で勇気を得たように、 1人でも多くのRubist に勇気を与えることができれば光栄に思います。

cf. https://rubykaigi.org/2019/presentations/ujm.html#apr20

当日の資料

speakerdeck.com

binding.pry がなぜ動くのか?今更ながら調べてみた

TL;DR

  • binding.pry は、Kernel#bindingObject#pry に分けられる。
  • Kernel#binding はコンテキストの環境情報を束縛したBinding オブジェクトを返す。
  • Object#pry はREPL プログラム。

そもそも、binding.pry とは?

Ruby を使っている方なら、一度はbinding.pry を利用したことがあるでしょう。

そう、debug するときにお世話になるあれです。

しかしながら、なぜあのような挙動になるのか知っている人は少ないと思います。 コード中にbinding.pry を記述し当該のコードを実行するだけで*1、 なぜかプロンプトが出現します。

     9: def name
 => 10:   binding.pry
    11:   puts @name
    12: end

[1] pry(#<Sample>)>

なぜでしょう。

wakaranai...

ということなので、今更ながら調べてみました。

そもそも、pry とは何なのか。

Pry is a runtime developer console and IRB alternative with powerful introspection capabilities. Pry aims to be more than an IRB replacement. It is an attempt to bring REPL driven programming to the Ruby language.

cf. https://github.com/pry/pry#introduction

要はruntime developer console だと。 そして、REPL driven programming をRuby に導入することを目指すものらしい。

でつ。oO(はて。REPL とは何だろう。。。難しそう。。。)*2

REPL (Read-Eval-Print Loop) とは、入力・評価・出力のループのこと。 主にインタプリタ言語において、ユーザーとインタプリタが対話的にコードを実行する。

cf. https://ja.wikipedia.org/wiki/REPL

とのことです。

今回はこちらのREPL の処理を中心に、pry を紐解いていこうと思います。

と、その前に今回はbinding.pry がなぜ動くのか?という事なので、 Kernel#Binding メソッドについても調査していきます。

Kernel#binding

まずは、binding.pry の前半分の、binding

これは、gem pry に依存するものではなく、Ruby 組み込みライブラリKernel モジュールのメソッドです。 変数やメソッドなどの環境の情報を束縛した、Binding クラスのオブジェクトを返します。

def sample
  name = 'John'
  binding
end

eval('puts name', sample)
#=> John

cf. Binding

Kernel#eval の第二引数に渡すと、そのコンテキストで第一引数の文字列をRuby プログラムとして評価してくれます。

つまり、binding.pry を実行したときに必要な情報が取得できるのは、この人のおかげという事ですね。

でつ。oO(すてき。。。)

Object#pry

さて、binding.pry の残りの部分pry の部分を深掘りしていきます。

肝心の pry メソッドですが、gem pry のなかで定義されています。

class Object
  ...
  def pry(object = nil, hash = {})
    if object.nil? || Hash === object # rubocop:disable Style/CaseEquality
      Pry.start(self, object || {})
    else
      Pry.start(object, hash)
    end
  end
  ...

Open class を用いてObject クラスに、pry メソッドを定義しています。 Object クラスは全てのクラスのスーパークラス*3なので、Object#pry を定義することで、 全てのオブジェクトでpry メソッドが利用できるようになります。

実際にModule#method_defined? を使って確かめてみると。

p Object.method_defined?(:pry)
#=> false

require 'pry'

p Object.method_defined?(:pry)
#=> true

require 'pry' の前では Object クラスに pry が定義されていなにのに対し、 require 'pry' の後では Object#pry が定義されていることが確認できます。

さて、ここからはbinding.pry がコード中で実際に呼ばれたとき、何が起こるのか見ていきます。

コード中でbinding.pry を呼ぶと、 Object#pry にデフォルト引数object = nil が渡されます。 そして、Object#pry の内部で、Pry.start(self, object || {}) が呼ばれます。

  def self.start(target = nil, options = {})
    ...
    options[:target] = Pry.binding_for(target || toplevel_binding)
    ...
    driver = options[:driver] || Pry::REPL

    # Enter the matrix
    driver.start(options)
    ...
   end

Pry.start は全体で30行程あります。 長くなるのでメインの処理の関係する箇所のみ抜粋しました。

Pry.binding_for が呼ばれています。target が存在すれば target を、 無ければトップレベルスコープの binding が引数として渡されます。

binding.pry のケースでは、self(=binding)Pry.binding_for の第一引数として渡されます。

  def self.binding_for(target)
    return target if Binding === target # rubocop:disable Style/CaseEquality
    return TOPLEVEL_BINDING if Pry.main == target

    target.__binding__
  end

こちらのメソッドは渡されたtargetbinding を返します。 binding.pry のケースでは、self(=binding) が戻り値となります。

    options[:target] = Pry.binding_for(target || toplevel_binding)

その結果、options[:target]self(=binding)アサインされます。

Pry.start では続いてdriver に Pry::REPLアサインされ、Pry::REPL.start が呼ばれます。 options が引数として渡されるので、先ほどoptions[:target] としてアサインした束縛情報ももれなく渡されています。

    def self.start(options)
      new(Pry.new(options)).start
    end

    ...

    def start
      prologue
      Pry::InputLock.for(:all).with_ownership { repl }
    ensure
      epilogue
    end

Pry::REPLインスタンスが作成され、Pry::REPL#start が呼ばれます。 Pryインスタンスが生成され引数として渡されています。 また、この際Pryインスタンス変数@binding_stackoptions[:target] の中身がアサインされています。

やっと、主要の処理にたどり着きました。Pry::REPL#repl です。

感の良い方はもうお気付きですね!(感が鈍くても気がつきますね。。。)

そう、Pry::REPL#repl は、先ほど説明したRead-Eval-Print Loop です!

    def repl
      loop do
        case val = read
        when :control_c
          output.puts ""
          pry.reset_eval_string
        when :no_more_input
          output.puts "" if output.tty?
          break
        else
          output.puts "" if val.nil? && output.tty?
          return pry.exit_value unless pry.eval(val)
        end
      end
    end

コードを見てみると、何だか色々やってそうですが、 重要なのはPry::REPL#readPry#evalKernel#loop です。

でつ。oO(あれ、print が無い。。。)

read

Pry::REPL#read > Pry::REPL#read_line > Pry::REPL#input_readline という順で見ていきます。

    def input_readline(*args)
      Pry::InputLock.for(:all).interruptible_region do
        input.readline(*args)
      end
    end

input@pry 経由でPry::Config からdelegate されています。

  class Config
    ...
    def initialize
      merge!(
        input: MemoizedValue.new { lazy_readline },
        ...
    def lazy_readline
      require 'readline'
      ::Readline
      ...
    end

長くなりそうなので中間の処理を省きます。

上記の通りinput には::Readlineアサインされるので、 Readline.readline が呼ばれ、ユーザからの入力を取得します。cf. Readline

これがコード実行中にプロンプトが表示されて、入力待機状態になる現象の実態ですね。 無事ユーザからの入力部分は理解できました。

続いて、評価部分のeval を見ていきます。

eval

前出のPry::REPL#repl を見るとpry.eval(val) となっており、先ほど見たread の戻り値をPry#eval に渡しています。

ちなみに、ここで呼ばれているeval は、Pry クラスでoverride されており、Kernel#eval とは異なります。

Pry#eval > Pry#handle_line > Pry#evaluate_ruby と読み進めていきます。

  def evaluate_ruby(code)
    inject_sticky_locals!
    exec_hook :before_eval, code, self

    result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
    set_last_result(result, code)
  ensure
    update_input_history(code)
    exec_hook :after_eval, result, self
  end

こちらも途中の処理をだいぶ省きました。

Pry#evaluate_ruby の中で、current_binding.eval が呼ばれています。 Pry#current_binding は、binding_stack に格納されている現状のBinding オブジェクトを返します。 Pry#current_binding の戻り値のコンテキストで、文字列codeRuby のコードとして評価します。 ちなみに、多少処理がなされていますがcode の中身は、先ほどのPry::REPL#read の返り値です。

結局のところ、対象のbinding に対して、binding#eval を呼び出しているだけですね。

さて、ここまででreadeval までの処理が完了しましたね。

次は表示print の部分です。

print

実は先ほど見たPry#eval の中にprint の処理も含まれています。

Pry#eval > Pry#handle_line > Pry#show_result と掘り進めます。

  def handle_line(line, options)
    ...
      Pry.critical_section do
        show_result(result)
      end
    ...
  end
  def show_result(result)
    if last_result_is_exception?
      exception_handler.call(output, result, self)
    elsif should_print?
      print.call(output, result, self)
    end
    ...
  end

print の中身は、Pry::ColorPrinter.method(:default) の戻り値Method オブジェクトです。 そのMethod オブジェクトにcall メソッドを呼んでメソッドを実行しています。

require 'pp'
...
class Pry
  class ColorPrinter < ::PP
    ...
    def self.default(_output, value, pry_instance)
      pry_instance.pager.open do |pager|
        pager.print pry_instance.config.output_prefix
        pp(value, pager, pry_instance.output.width - 1)
      end
    end
    ...
  end
end

Pry::ColorPrinter.default の中で、pry_instance.pager.open によってfile を開きます。 ここで開くfile に関しては、設定によって変わります。

ブロックの中で、Pry::ColorPrinter.pp を呼び出します。

    ...
    def self.pp(obj, output = $DEFAULT_OUTPUT, max_width = 79)
      queue = ColorPrinter.new(output, max_width, "\n")
      queue.guard_inspect_key { queue.pp(obj) }
      queue.flush
      output << "\n"
    end

そして、ColorPrinter#pp を呼び出します。

    ...
    def pp(object)
      return super unless object.is_a?(String)

      text(object.inspect)
    rescue StandardError => exception
      raise if exception.is_a?(Pry::Pager::StopPaging)

      text(highlight_object_literal(inspect_object(object)))
    end
    ...

引数のobjectString 以外の時は、 キーワードsuper を呼び出し親クラスPPpp メソッドを呼び出しています。 それ以外のケースでは、ColorPrinter#text を呼び出します。

    ...
    def text(str, max_width = str.length)
      if str.include?("\e[")
        super("#{str}\e[0m", max_width)
      elsif str.start_with?('#<') || %w[= >].include?(str)
        super(highlight_object_literal(str), max_width)
      else
        super(SyntaxHighlighter.highlight(str), max_width)
      end
    end
    ...

表示する文字列str の内容に応じて処理を変更しています。 基本的にはこちらもキーワードsuper により、親クラスのPP#text を呼び出しています。

この一連の処理によって、結果が出力されます。

loop

あとはこれを外側のループで回すだけです。

でつ。oO(loop は特に書くことが無い。。。)

ここまでの一連の流れがbinding.pry ないしは、pry メソッドの正体です。 pry というgem 全体で見ると処理も多く、コード数もそれなりにあります(20,000 行強*4)。

ただ、REPL に関する処理は、意外とシンプルなようでした。

所感

今まで何となく使っていたbinding.pry ですが、実際に調べてみて、 ブラックボックス化されていたことを明らかにすることができました。

# 今まで
binding.pry == 便利な魔法の呪文

# 今
binding.pry == REPL プログラム

頭の中でbinding.pry の単語をアップデートすることができました*5

最後まで読んでいただきありがとうございます🙇‍♂️

参考

*1:gem のインストールが必要。

*2:でつ: 社のSlack でご活躍のスヌーピーさん。

*3:実際にはBasicObject クラス(Ruby 1.9 以降)という、Object クラスの親にあたるクラスが存在します。

*4:コード量計測には'AlDanial/cloc' を使用。

*5:pry は様々なコマンドが利用出来たり、ハイライトが効いたりと単純なREPL プログラム以上のものです。