pokutuna.com

pokutuna

Web Developer / Software Engineer
Hyogo, Japan

Blog Entries

  • ぽ靴な缶

    Apple Watch を買って半年

    去年の9月末に買いました。 Series 9 41mm シルバー GPS 発表を見るたびに欲しいなと思うものの、冷静に考えると要らないよな、という結論に行き着くので買ってなかった。常にスマホ持ってるでしょ。欲しい → 要らん → 欲しい というのを年1でやりつつ、ついに買ってしまった。 買ってからは便利で、風呂と充電以外は常に着けている。 生活をシャキッとさせたい フルリモートなので家から出る頻度が減って、体力も落ちだんだん太ってきた。運動習慣を付けたいけど、無策では続けられないので記録を付けるおもちゃが欲しい。他にも睡眠や心拍など Watch で体をモニタリングして遊びたい。自転車に乗っていた頃は記録に楽しさがあった。サイコンつけるし心拍計も胸に巻いてた。変化が分かると成長が見えるし満足できる。 TODO リストをもっと生活に密着させる狙いもある。Things を愛用していたけど、ここ何年も活用できてなかった。今は仕事のタスクは仕事で管理するし、生活系は記憶に頼ってもなんとかなる。なんとかなるけど、サプリ飲むとか本読むとか買い物とか、それなりに忘れているので確実に遂行しつつ習慣を作りたい。 バンド選び 買う前にずっと迷っていたのはバンド。 結局バンドはデフォルトのスポーツバンドにした。シリコン的なプニャっとしたやつ。 スポーツバンド スポーツバンド Apple Watchのバンドを購入 - Apple(日本) Watch を持ってる同僚の話を聞いて、 ブレイデッドソロループ > スポーツループ > スポーツバンド ぐらいの感じで、実物見て決めようと思っていた。しかし欲しさが最高潮の加速を使ってヨドバシで買ったので選ぶ余地が スポーツバンド or スポーツループ しかなかった。個別にバンドを選べるのは Apple Store か通販だけである。 ソロループ系は伸びるのを想定してサイズチャートより1サイズや2サイズ下が良いという真偽不明情報に惑わされて踏み切れないし、スポーツループの実物は思ったよりペラペラで、軽くて柔らかいのは分かるけど、タイトめに締めないと Watch の重さに対して慣性やズレが不快そうだなと見送った。 結果的にスポーツバンドで満足している。 4 運動などタイトにしたいとき 5 普段使い 6 洗い物したり干渉するとき むしろ締め付けず使い分けれるのが良い。通気性はないので汗をかくと多少気になるけど、そのまま時計ごとじゃぶじゃぶ洗える。冬場は手袋やパーカーの袖口のリブなんかが干渉するのでやや鬱陶しい。 腕 使ってみて いろんなものが腕で済む 時間が分かって便利、とよく言うけど、たしかに常に時計とカレンダーが腕にあるのは素朴な便利さがある。 常に次の予定がぱっと見れる。特に出社した時など、ミーティングあるのは分かっているけど会議室どこやねん、と調べるのに何かを開かなくて良い。 MFA も腕で見れる。トークン入力画面が出るやいなや端末探したり席を立つ必要がないのが良い。MFA には Authy を使っていて iPhone アプリ側のがそのまま見れる。パスワード自体も 1Password から選択的に Watch へ送っておくことができる。 腕から Nature Remo により家電が操作できる。常に腕に付いてるので、布団の中で携帯探さなくて良い。 ズボラな用途だと、布団に入ったけど、何かが PC のスリープを止めているな...まぶしい...って時に時計から pmset sleepnow している。Shortcut.app で ssh するショートカットを用意しておくとよい。 地図が腕にあるのも悪くない。 スマホ出してロック解除して地図見て、という動作をかなり頻繁にやっていることに気づく。今まで Apple Map を使っていなかったけど、Watch との連携の良さから使うようになった。Google Map の Watch アプリは地図は出ないが、スマホ側で検索したルート(主に乗り換え)を Watch で見れるので使い分けている。カレンダーの予定に場所を入れる機能も Watch でルートをシュッと表示できるので入れると便利。 母艦との連携 iPhone・Mac とのシームレスな連携がすごい。 iPhone 側のアラームは Watch も鳴って、Watch 側で止めれる、iPhone 操作している時に鳴った場合は時計は鳴らない、とかも大変良いです。外やマスク付けている時は Watch が FaceID より速く反応してロック解除できるのも良い。Mac のロックも解除できる。 通知も同期している。 iPhone にバンバン来る通知に対し、一覧を眺めて読み飛ばす運用をしていた。でもそのノリで時計で受けるのは鬱陶しすぎた。 最終的に id:cockscomb に教えてもらった時間指定要約を使って、いらねと思ったものを要約送りにしていくと必要なものだけ Watch に届くようになるし、iPhone 側は雑に受けつつ興味あるやつだけざっと見る運用ができた。 ただ iPhone 側の時間指定要約は、おしゃれなレイアウトで表示されるので、エッチな画像のレコメンドや YouTube のサムネがロックスクリーンに表示されうる。ロック中は通知を出さないようにしているが、携帯と一瞬目が合うと解除される。たまに気まずい。 Watch を買うと通知を整理する動機が生まれるし、Watch ユーザのほうが世のアプリのエンゲージメントが下がっているみたいなことが起きているんじゃないか。LINE の企業アカウントの通知とかも止めまくったし。 端末を超えて集中・睡眠モードが同期して動くのも良い。 あとここ数年ぐらいの iOS のアップデートの意図みたいなのがしっくりきた。ロック画面のカスタマイズがなんでこんな感じなの...と微妙に思っていたけど Watch と体験が共通になっているし納得感はある。 あと通知の持ち上げたとき周りの挙動がいいよね。 かわいい通知 電池の持ち 自分の使い方だと、常時点灯で1日使って 40~50% ぐらい残る。100% から 40 時間ぐらい持つ。 丸2日は持たないが、充電せず寝てしまっても十分バッファがある。 カタログスペックでは 18 時間という不安になる数字だけど、かなり時計使いまくってる状態での試験やね。バッテリなんて得てしてカタログを下回る体験だけど、倍以上保つのは意外だった。 意外と持つ 充電面倒かなと思っていたけど、意外とそうでもない。 45分で 0% → 80% のようで、実際そのぐらい。風呂の時間だけで 100% になれば最高なのだが...ちょっとは待つ必要がある。 充電自体より、ケーブルの管理が面倒。出張や外泊に持っていくものが1個増える。 サードパーティのケーブルはレモン市場感が激しく、急速充電言ってるだけだったり 5W 出てないものだったりする。そしてまともなものは MFi 取っていて高い。 Apple Watch 磁気充電ケーブル(1m) Apple(アップル) Amazon Anker 3-in-1 Cube with MagSafe: マグネット式 3-in-1 ワイヤレス充電ステーション/USB急速充電器付属/ワイヤレス出力/Apple Watchホルダー付/MFi認証/iPhone15 Apple Watch対応 Anker Amazon 睡眠の記録 睡眠トラッカーの AutoSleep が良い。 睡眠には、気絶睡眠モデルを採用しており、寝ようと思って眠ることはあまりなく、いつのまにか気絶している。十分寝たら意識を取り戻す。そういう暮らしを送っています。支障がないようウィンドウを広く取っていて、夕食後(20時) ~ 愛する妻が起きる(7時)まで、任意気絶する。 そういう感じなので、自然と10時間寝て元気なこともあれば、3時間しか寝てないこともある。記録が残っていれば眠かったり疲れてたりするのが睡眠不足かどうか切り分けられる。仕事の忙しさやストレスが睡眠に反映されているのも読み取れたりする。 夕食後に寝てない時期 気絶睡眠法の欠点として寝る前の準備というものができない。昔から Sleep Sycle を使っていたけど、iPhone に充電ケーブルを挿しつつアプリを起動して枕元に置く作業は難しすぎる。いびきを録音して聞けたりは大変楽しいのだが、意図して入眠する日だけ使える状態だった。 Apple Watch を使った睡眠記録には AutoSleep が良くて、いつ寝ても睡眠検出して記録してくれるし、起きたタイミングも勝手に残る。判定が間違ってると思うことはそんなにない。 特に「人間が寝るのは1日1回である」という非現実的な仮定を置いてないのがいい。複数回寝れるし記録が残る。 晩飯食べたあと床で30分気絶して、ベッドに這って移動してまた寝るとか、昼休みに30分寝るとか、朝飯食べたあとに二度寝するとか、現実には1日に何回も寝る。1回なわけねーだろ。 現実の睡眠活動 アプリの作りも、常にセンシングして頑張っている感じでなくヘルスケアのデータを複数突き合わせて活用している感じなのも好ましい。母機の iPhone いじってたらそれは起きてる時間だよね、とか。 リングやゲージの UI は特に分かりやすくはないです。 入力 意外とキーボード入力できる。 込み入った返事はやる気起きないが、ack 程度の内容や、TODO を 1 行だけ入力など時など普通に時計でやっている。音声入力も割と使う。 意外と入力できるキーボード Series 9 なら使えるダブルタップは良いけどタイト目につけていないと反応がわるい。今のところ通知閉じるのと、料理中に手が汚れたままタイマー止めるのが主な用途である。 アクセシビリティの Assistive Touch を使うと、色々ジェスチャで操作できてなかなかすごい体験。一度やったほうがいい。それなりには大変だけど片腕でも一通りの操作ができる。手を2回握りしめる、とかにアクションが割り当てられている。 Apple Watch で AssistiveTouch を使う - Apple サポート (日本) ダブルタップはプライマリのボタン1個押す程度のアクションしかできないので、普段もクレンチ(手を握りしめる)でセカンダリの動作ができるようになってほしいな。 運動 買ってから週に 2 ~ 3 回運動していて、意外と続いている。近所の坂の上の神社まで行って帰ってくる、約 40 分。 これ読んでインターバル速歩をやっている。 ウォーキングの科学 10歳若返る、本当に効果的な歩き方 (ブルーバックス) 作者:能勢 博 講談社 Amazon 要は (ワーク:心拍ゾーン2以上を3分 → レスト:心拍ゾーン1を3分) * 5 をやれという話だけど、運動生理学の話がおもしろい。mol から消費酸素の体積計算したりした。知らない分野の教科書みたいな読後感。 世にアプリも色々出ているが、Apple のフィットネスで独自のワークアウトを作れて、心拍ゾーン外れたら通知したりできる。これ Apple Watch からしか編集できないようで、チマチマした作業が発生して面白い。 時計でワークアウトを編集する 作ったワークアウトは共有もできる。iOS で開くと Watch に追加できる。 https://storage.googleapis.com/pokutuna-public/interval-walking.workout 本で紹介されている運動は老人向けで、だんだんと心肺機能がマシになってきたのもあり、平地の早歩きでは心拍が上がらないので、普通に走り始めた。傾斜がきついところは歩いている。するとゾーン5も使う羽目になる。 それにしても VO2max が低すぎる、35 て。 痩せにくいと思っていたけどショボすぎないか、45 ぐらいには持っていきたい。一方心拍回復は 30 まで戻ってきた。 Watch アプリのつくり アプリが全体的に割り切った作りものが多い。 Apple Map のルート検索の出発地点は現在地からのみ。出発地点や経由地を設定したければ iPhone からしろという割り切りは良いのだが、電車3路線アクセス可能な立地に住んでおり、なかなか狙ったルートで検索できないので時計から電車の時間調べるのは諦めてる。 アラームやリマインダーなど、リストに追加する系 UI の追加ボタンが一番下にありがちなのもツラい。「ヘイシリ n 分後に起こして」という指示を日々やっているので、アラームのリストはスクロールが苦痛なほど長くなっている。時計でも右上に "+" ボタン置いてくれよ。 ピークタイム スマホ経由で通信する都合上、ネットワークエラーやタイムアウトに出くわしやすい気がする。やたらローディングのままだったり、タイムアウトした時にアプリをキルしないと何もできなかったり。 微妙なアプリの作りの悪さもありがち。 Watch の Siri のサジェスト押した時の動作定義してないのか、最低限アプリが起動すればいいのだが謎のウィンドウが開いてくるくるするだけとか。 母機の iPhone を経由する遅延やリトライがそこそこある上に、状態を iPhone 側に保存していたら通信して読まないといけないだろうし、考えることが多く画面も小さくフィードバックも難しそうではある、その上ユーザは限られてるとなると力も入らない気持ちは分かる。 価値 収支 図にするとこんな感じ。 腕に時計を着け続けるのは明らかに邪魔なのだが、様々な便利さにより総合的には良い。 追記 あたりまえすぎてタッチ決済に言及していなかった。 まじめにやってくれ天気.app

  • ぽ靴な缶

    OSS 観光名所を貼るスレ

    これは はてなエンジニアアドベントカレンダー2023 2日目の記事です。 はてなエンジニア Advent Calendar 2023 - Hatena Developer Blog はてなエンジニアのカレンダー | Advent Calendar 2023 - Qiita トップバッターは緊張するけど、順番が回ってくるまで長い間ソワソワするのも嫌、という理由で例年2日目を狙うようにしている id:pokutuna です。今年も成功しました。 観光名所とは 目を閉じれば思い出す、あのコード... あの Issue... あなたが Web 系のエンジニアであれ、趣味で開発している方であれ、必要に応じてライブラリやフレームワークのコードを読むのはよくあることでしょう。公開の場で開発されているソフトウェアは、ソースコードだけでなく、開発コミュニティでの議論やバグ報告なども見ることができます。 リポジトリを覗き見していると、思いもよらない実装や、記憶に残るディスカッション、バグレポートまでいろいろな営みが見つかります。 私はそういったものを「観光名所」と呼んでコレクションしています。 今日はよく知られているソフトウェアの GitHub 上にある観光名所をピックアップして紹介します。 観光名所たち __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED (facebook/react) facebook/react@60ad369 - packages/react/src/React.js#L128 export { ... ReactSharedInternals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, これはちょっと有名かも、ReactSharedInternals が export される際の物騒な名前。React の内部状態が入っています。 まあ必要があって export しているわけで、テストや react-dom など他の packages/ 以下からちょいちょい参照されている。package として公開しているが、これに依存した機能なんて作るなよというメッセージが明確に表現されています。まあドキュメントやコメントで言っても読まれませんからね。 Node.js の HTTP ヘッダの小文字化 (nodejs/node) nodejs/node@60ffa9f - lib/_http_incoming.js#L279 function matchKnownFields(field, lowercased) { switch (field.length) { case 3: if (field === 'Age' || field === 'age') return 'age'; break; case 4: if (field === 'Host' || field === 'host') return 'host'; if (field === 'From' || field === 'from') return 'from'; if (field === 'ETag' || field === 'etag') return 'etag'; if (field === 'Date' || field === 'date') return '\u0000date'; if (field === 'Vary' || field === 'vary') return '\u0000vary'; break; case 6: if (field === 'Server' || field === 'server') return 'server'; if (field === 'Cookie' || field === 'cookie') return '\u0002cookie'; if (field === 'Origin' || field === 'origin') return '\u0000origin'; if (field === 'Expect' || field === 'expect') return '\u0000expect'; if (field === 'Accept' || field === 'accept') return '\u0000accept'; break; case 7: if (field === 'Referer' || field === 'referer') return 'referer'; if (field === 'Expires' || field === 'expires') return 'expires'; ... Node で HTTP ヘッダを扱う際、ヘッダ名を小文字で扱っていることに気づきます。RFC2616 → RFC7230 → RFC9112 の歴史ある仕様にあるように、ヘッダ名は大文字小文字を区別しないので、すべて小文字に寄せているようですね。 何度も実行されるところなので、パフォーマンス優先のためになかなか激しい実装になっています。toLowerCase を呼ぶ回数を減らすため、一般的なヘッダはハードコードされており、文字列比較の回数を減らすため前段で文字列長で分岐しています。 返す文字列の1文字目がフラグになっている、というのもなかなかです。同じヘッダが複数回出現する場合の区切り文字や、Cookie & Set-Cookie の扱いを制御しています。 VSCode のコマンドがローカライズされる (microsoft/vscode) Don't localize command names on the command palette · Issue #4679 · microsoft/vscode VSCode の開発版である Insiders Build にリリースされた変更。 コマンド名が翻訳されて、git pull ではなく git プル と入力する必要がでてくる。やめてくれという意見で CJK 圏の気持ちが一つになった事件。 Issue を立てるだけでなく、繰り返し問題を説明する @espresso3389 さんの活躍が光る Issue です。これが安定版に降ってこなくて本当に良かったですね。ソフトウェアをローカライズする際の難しさも垣間見えます。 A picture of a cute animal (moby/moby ほか) moby/moby@75546e1 - .github/PULL_REQUEST_TEMPLATE.md Please provide the following information: ... **- A picture of a cute animal (not mandatory but encouraged)** moby は、以前モノリシックな構造だった Docker リポジトリをコンポーネント化していったもので以前は docker/docker でした。今も Docker の実装に使われています。その moby の Pull Request テンプレートには、かわいい動物の画像を貼るコーナーがあります。 例 https://github.com/docker/compose/pull/11213 (moby じゃなかった) https://github.com/moby/moby/pull/32061 (アスキーアート) https://github.com/moby/moby/pull/27455 (どういう状況?) https://github.com/moby/moby/pull/34895 (🐼で済ませる) でも最近の Pull Requests を見るに、そんなに貼られてはいなさそう。 その他 docker 関連リポジトリにおいても動物画像コーナーがしばしば見られます。 docker/compose@c582470 - .github/PULL_REQUEST_TEMPLATE.md docker/cli@c1455b6 - .github/PULL_REQUEST_TEMPLATE.md Steve Wozniak is not boring (moby/moby) moby/moby@75546e1 - pkg/namesgenerator/names-generator.go#L852 if name == "boring_wozniak" /* Steve Wozniak is not boring */ { goto begin } こちらも moby から、Docker コンテナの自動命名にある唯一の例外。 docker run でコンテナを起動した際、ランダムな名前が割り当てられるのはこの names-generator.go の実装によるものです。"形容詞" と "科学者やハッカーの名前" の2つのテーブルから選んで結合したものになる。 形容詞のテーブルに boring、人名のテーブルに wozniak が含まれていますが、boring_wozniak という名前がコンテナに割り当てられることだけはありません。なぜなら Apple 創業者の Steve Wozniak は退屈ではないので。 goto で戻ってやり直しているのも普段あまり見ないので面白いですね。 そういえば Elasticsearch の node 名は Marvel キャラクターから選ばれるんだっけ、と見に行ったら 5.0 からなくなっていた。めっちゃ前じゃん elastic/elasticsearch@v2.4.6 - core/src/main/resources/config/names.txt Trick and AttributeError 事件 (pypa/pipenv) Halloween easter egg breaks · Issue #786 · pypa/pipenv pipenv は Python のインタプリタと依存ライブラリのバージョンを管理する bundler ツール。 普段のプログレスバーは 🐍 の絵文字で表示されるところ、ハロウィンだけ 🎃 になるというイースターエッグが仕込まれていました。しかしそこにバグがあり、ハロウィンだけ例外が出て依存をインストールできなくなる事態に。 ちょうどこれでデプロイ不能になってハマったのでよく覚えている。ここがいきなり壊れると思わないだろ。 累計100万DLを突破したダイエットアプリ(無料)の『もぐたん』! (google/zetasql) google/zetasql@589026c - zetasql/compliance/testdata/strings.test#L911 -- ARRAY<STRUCT< STRING, formatted_description STRING >> [ { "累計100万DLを突破したダイエットアプリ(無料)の『もぐたん』!\nおかげさまで、ヘルスケア/フィットネス 無料カテゴリで1位獲得!\n\n◆かんたんスタンプ入力 \n文字で書かなくても食べ物スタンプで簡単に記録出来ちゃう!\n\n◆『もぐたん』がみんなを応援\n入力する度にもぐたんがゆるくて可愛いコメントをくれるよ!\n毎日体重を入力して『もぐたん』の「きせかえ」をGETしよう!\n\n◆ダイエットの成果はグラフでチェック\n体重を入力するとグラフに反映されるから変化がまるわかり!\n摂取カロリーの推移もグラフでチェック出来ちゃう!\n\n◆体重と一緒に運動スタンプを入力\n運動もスタンプでかんたん入力!\n毎日どのくらいダイエットしたかがひと目でわかるよ!\n\n◆ 自動カロリー計算機能\nプロフィールを入力すると、あなたに合った摂取カロリーの目安がわかるよ!\n\nhttps://itunes.apple.com/jp/app/daietto-ji-lumogutan-ke-aiisutanpude/id882365789", '"累計100万DLを突破したダイエットアプリ(無料)の『もぐたん』!\\nおかげさまで、ヘルスケア/フィットネス 無料カテゴリで1位獲得!\\n\\n◆かんたんスタンプ入力 \\n文字で書かなくても食べ物スタンプで簡単に記録出来ちゃう!\\n\\n◆『もぐたん』がみんなを応援\\n入力する度にもぐたんがゆるくて可愛いコメントをくれるよ!\\n毎日体重を入力して『もぐたん』の「きせかえ」をGETしよう!\\n\\n◆ダイエットの成果はグラフでチェック\\n体重を入力するとグラフに反映されるから変化がまるわかり!\\n摂取カロリーの推移もグラフでチェック出来ちゃう!\\n\\n◆体重と一緒に運動スタンプを入力\\n運動もスタンプでかんたん入力!\\n毎日どのくらいダイエットしたかがひと目でわかるよ!\\n\\n◆ 自動カロリー計算機能\\nプロフィールを入力すると、あなたに合った摂取カロリーの目安がわかるよ!\\n\\nhttps://itunes.apple.com/jp/app/daietto-ji-lumogutan-ke-aiisutanpude/id882365789"' } ] zetasql は BigQuery や Cloud Spanner 内で利用されている Google の SQL Parser & Analyzer です。 その utf8 文字列のテストデータとして「もぐたん」という iOSアプリの App Store 説明文らしきものが使われています。そこは Play Store じゃないんかい。 zetasql は、BigQuery 大好きパーソンが中を知りたい時に当たれる数少ない公開コンポーネントです。謎に満ちており、OSS ではあるもののコミュニティ主導ではなく ZetaSQL Team ユーザが数週間に1回変更をまとめて push する、人の侵入を望まない霊峰のような風情。 もぐたんは現在サービス終了していますが、かわいいクマチャンが出てくるアプリです。zetasql との温度差で交互浴の気分になります。 ダイエット・カロリー・体重記録アプリもぐたん(applion より引用) 参考 Google の SQL parser/analyzer の ZetaSQL とは何であるか | by apstndb | google-cloud-jp | Medium 公開論文から学ぶ Google のテクノロジー : パート 3:データベース技術編 | Google Cloud 公式ブログ Promise.race で DNS & IP 両方にリクエストを投げる (googleapis/gcp-metadata) googleapis/gcp-metadata@27f0a12 - src/index.ts#L186-L187 let responded = false; const r1: Promise<GaxiosResponse> = request<T>(options) .then(res => { // ... }) const r2: Promise<GaxiosResponse> = request<T>(secondaryOptions) .then(res => { // ... }); return Promise.race([r1, r2]); これは Google Cloud のメタデータサーバーにリクエストする実装です。 メタデータサーバーは GCP 内のネットワーク内から到達でき、実行環境に応じた情報取得や認証を行うため、ほとんどのクライアントライブラリが内部的に叩いています。 ここではメタデータサーバーの metadata.google.internal. と、それを解決したリンクローカルアドレスの 169.254.169.254 に並行にリクエストを投げて先に成功した方を使うという実装になっています。 そんなことしていいの、と驚くけど、GCP 内の名前解決が遅い環境では 169.254.169.254 が先に結果を返すでしょうし、GCP 外のユーザのローカル環境などでタイムアウト待ちになったとしても metadata.google.internal. が解決できないので名前解決程度の短時間で失敗できる、という感じでしょうか。合理的ではあります。こんなコアっぽいところでリクエストを倍にしちゃうんだ。 関連: GCP の Application Default Credentials を使った認証 - ぽ靴な缶 命名に関する議論 命名に関する議論は紛糾しがちです。 GitHub は 2020 年 10 月にデフォルトブランチ名を master から main に変更しました。日本語圏だけでもいろいろな意見が飛び交いましたね。 The default branch for newly-created repositories is now main - The GitHub Blog 先程の Docker コンテナ命名の実装についても、議論の末に変更を凍結する判断がされています。 Freeze the namesgenerator package against new additions by tianon · Pull Request #43210 · moby/moby このコメントの一部を機械翻訳し、調整したものを引用します 私たちはこの変更についてメンテナ会議で議論し、私たち全員がこのパッケージの最初の アイデアを気に入っていたにもかかわらず、何年もかけてこのパッケージは 望ましい以上のメンテナンスが必要になり始めたという結論に達しました。 いくつかの例を挙げますと、何年もの間、名前の組み合わせが不幸な組み合わせになったり、形容詞がすべての状況に適していなかったり、否定的な意味を持つようになったり、リストの人々が物議を醸すようになったりしたため、私たちはリストの変更を余儀なくされてきました。さらに、技術的な制限(姓が一意でないこと、名前の長さ、名前がアスキーに限定されているため、暗黙のうちに多くの地域の名前が除外されていること)もあり、事態を複雑にしています。 リンクされているコミットでは、形容詞の cocky は人に付けるのは適切でなかったり、kickass, insane など俗語的にはポジティブな意味(ヤバすぎ、のような)でも、フォーマルな文脈では厳しいので消したり置き換えられたりしています。 この "物議" が指すのは、エプスタイン事件において疑惑のある Marvin Minsky や、それへの言及が問題となった Richard Matthew Stallman についての話で、人名テーブルから除く変更が行われています。 リチャード・ストールマン氏、MITの役職とFSF総裁を辞任 エプスタイン関連コメントへの批判で - ITmedia NEWS かつてはおもしろ機能だったものが、社会的な価値観の変化やより広い人々を包摂するにつれて、不適切とみなされるようになっていく、ということが起きています。 他に命名に関する議論で思い出されるのは、FactoryGirl や Tsunami でしょうか。観光名所というと面白がっているニュアンスで聞こえるかもしれませんが、fun ではなく controversial な、記憶に残るものとして紹介します。 FactoryGirl が FactoryBot に変更 (thoughtbot/factory_bot) Repository Name · Issue #921 · thoughtbot/factory_bot こちらは Ruby のテストデータのファクトリライブラリである FactoryGirl が、FactoryBot にリネームした際の議論。 FactoryGirl は、Factory パターンと Rolling Stones の曲に由来する名前ですが、「名前の由来はなんなの?」という質問に端を発し、女性差別的ではないか、男性多数なソフトウェア業界のバイアスがあるのではないか、という議論から FactoryBot にリネームされました。 リネーム反対意見に同意する emoji の数や、女性による変えなくて良いというコメントが繰り返し言及される中(「当の女性が問題にしていないじゃないか」的な)、冷静にリネームの判断を下していてすごいですね。6 年前の話ですが、今やると emoji の傾向も大分変わるんじゃないでしょうか。不快だと思っていてもこの荒れた Issue では表明するのも難しいでしょう。 一方 FactoryGirl の Python 版といえる FactoryBoy はそのまま行くという判断をしています。 factory_girl --> factory_bot by alexgleason · Pull Request #442 · FactoryBoy/factory_boy Consider renaming to FactoryPy or the like · Issue #912 · FactoryBoy/factory_boy · GitHub Tsunami の命名に関する議論 (google/tsunami-security-scanner) I'm not sure if "Tsunami" is a good name. But I need your opinion. · Issue #5 · google/tsunami-security-scanner 津波のような攻撃から身を守るセキュリティスキャナーという命名ですが、Tsunami って命名はどうなの? 東日本大震災の津波を思い出す人もいるんじゃない? という Issue です。master/slave や whitelist/blacklist は、どこか外の話のように感じる人も多いと思いますが、これは日本人が当事者になったトピック。 当時はてなブックマークでも話題になっていました。 Googleのセキュリティスキャナー「Tsunami」、名称がGitHubで議論呼ぶ 関係者が参加し釈明 - ITmedia NEWS 性別の話に比べ、かなり抑制的に議論が行われていると思います。津波という名前だから破壊する方のツールかと思った、という尤もな指摘もあります。 ...それはそれとして、この議論の数ヶ月後に、google/tsunami が push されています。TSUNAMI (TypeScript Untar Multiple Reads) の略だそうです。偶然でしょうが、変なオチがついた気持ちになりました。 XML は暴力ではない (sparklemotion/nokogiri) Removing reference to violence. · sparklemotion/nokogiri@ddd8e1d - XML is like violence - if it doesn’t solve your problems, you are not - using enough of it. - ポリティカルコレクトネス的な変更で思い出すのは Nokogiri です。Ruby の XML パーサーですが、README から以下の行が暴力を賛美しているということで削除されました。 XML is like violence - if it doesn’t solve your problems, you are not using enough of it. XML は暴力のようなもので、それで問題が解決しないのであれば、使い方が足りないのだ。) まあ明らかにジョークだし、このぐらいいいんじゃないの...と思うものの、暴力に怯える状況で XML をパースする際には複雑な気持ちになるかもしれません。 自分がどの立場になるか、という問題は常にあります。 Facebook にクビになった人は、React の __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED を面白がれるでしょうか。いやしかし、他者の痛みを想像しつつも、勝手な想像で他人の喧嘩をしないほうがいい、というのが私の気持ちです。 もはや GitHub デフォルトブランチが main なのが当たり前になり、むしろ master を見ると古臭く感じるようになりました。そんな心情の変化に時代の流れを感じますね、とここまでを締めることにする。 その他小粒なもの 特に説明しても面白さに資さないけど、記憶に残るもの 猫がキーボードの上を歩いた結果立った Redis の Issue ///33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333-g=-[=. · Issue #3909 · redis/redis if enabled then "Disabled" まあ稀にこういうことをする羽目に陥る hashicorp/terraform-provider-azurerm@v2.67.0 - azurerm/internal/services/network/subnet_resource.go#L524-L533 Google Analytics の dimesion1 ~ dimension200 までの型定義、metrics1 ~ metrics200 もある DefinitelyTyped/DefinitelyTyped@ad1ea50 - types/google.analytics/index.d.ts#L84-L283 OSS 以外 タイトルの引き欲しさに OSS と書いたので、ここまでオープンソースライセンスと言えるものを挙げてきました。それ以外で記憶に残っているものをちょっと紹介します。 "You are not expected to understand this" (Version 6 Unix) 超有名な一節。コードが分かる人に比して圧倒的にコメントが流行っている。僕もわかりません。 BSD で配布されているようですが原典的にはこの枠で。 2230 /* 2231 * If the new process paused because it was 2232 * swapped out, set the stack level to the last call 3333 * to savu(u_ssav). This means that the return 2235 * actually returns from the last routine which did 2236 * the savu. 2237 * 2238 * You are not expected to understand this. 2239 */ 2240 if(rp->p_flag&SSWAP) { 2241 rp->p_flag =& ~SSWAP; 2242 aretu(u.u_ssav); 2243 } 解説の翻訳 あなたが見た中で最も有用なコードコメントは何ですか? - Quora SQLITE_TEMP_FILE_PREFIX "etilqs_" (mackyle/sqlite) mackyle/sqlite@18cf471 - src/os.h#L65-L79 #ifndef SQLITE_TEMP_FILE_PREFIX # define SQLITE_TEMP_FILE_PREFIX "etilqs_" #endif SQLite は軽量でファイルベースのデータベースです。著作権を放棄した Public Domain で公開されています。 身近なモバイルアプリやブラウザのローカルなデータベースとして組み込まれていたりします。Chromium の履歴やブックマークでも使われているようですね。SQLite abstraction layer そんな SQLite の一時ファイルは、sqlite を逆さに読んだ etilqs_ が prefix になっています。 理由はこちらの @EzoeRyo 氏のツイートでどうぞ。 マカーフィーがSQLiteを使っていて、C:\tempに一時ファイルを作ったため、ファイルを見て疑問に思った馬鹿なユーザーがsqliteを検索し、出てきた開発者の電話番号に「テメェ責任者かコラ、ファイル消しやがれゴルァ」という迷惑電話をかけまくったため、逆さ読みのetilqs_に変更された。 — 江添亮 (@EzoeRyou) 2023年6月13日 おわりに コレクションしていた観光名所を一通り放出しました。 みなさんの知る観光名所はどんなものがあるでしょうか? コメントやはてなブックマークコメントでぜひ教えてください!! チャンネル購読と、高評スターもお願いします。 また、労働をしていると社内の開発リポジトリに観光名所を見つけることもあります。きっと皆様の会社にもあることでしょう。 様々なしがらみで修正できずそのままになっている typo 議論が白熱しすぎてもはや喧嘩している Issue デカい障害を引き起こした名コミット 狂った命名 遺言に見えるコメント Revert を Revert した回数最高記録 いちばん長い SHA1 のゾロ目を探して遊ぶ などなど、興味がある方はこちらから入社してください。日本全国フルリモートOK!! hatena.co.jp 実用的な情報 ちなみに GitHub のソースコード表示中に y を押すと、URL が main などブランチ名から コミットID が含まれるものに変わります。こういう記事や、ドキュメントを書くときに便利ですね。ファイルへのパーマリンクを取得する - GitHub Docs また、cocopy でリンクテキストを生成するとさらに便利ですよ。 blog.pokutuna.com こんな関数で、デフォルトは Markdown、Shift キーを押している時は Scrapbox 記法でコピーしています。 ({title, url, modifier}) => { const pattern = /https?:\/\/(.+)\/(?<user>.+)\/(?<repo>.+)\/blob\/(?<rev>[^/]+)\/(?<file>[^#]+)(?<hash>#.+)?/; const g = pattern.exec(url).groups; title = `${g.user}/${g.repo}@${g.rev.substr(0,7)} - ${g.file}${g.hash || ''}` return modifier.shift ? `[${title} ${url}]` : `[${title}](${url})`; } この記事は はてなエンジニア Advent Calendar 2023 2日目の記事でした。 明日の担当は id:mechairoi さんです。楽しみですね。 blog.chairoi.me 追記 ブックマークありがとうございます。 挙げてもらった観光名所にリンクしておきます。 ちょっと小粒よりだけど Sidekiq にある❤という名前のメソッドはおもしろ命名なので観光名所としてオススメですhttps://t.co/FkHiOH6amS OSS 観光名所を貼るスレ - ぽ靴な缶 https://t.co/Js9w9VQlZI — 藤秋 (@f_subal) 2023年12月2日 「デカい障害を引き起こした名コミット」の例だとaxiosでXSSを防ぐために"on〇〇"を含むクエリパラメータを全部エラーにしたやつが思い出されるかなhttps://t.co/z20FtZkLzx — 藤秋 (@f_subal) 2023年12月2日 TypeScript が急に 3.3.3333 ってバージョンを作って怒られる回 https://t.co/nnqwJrUGBG とか、Jest が10000個目の PR で馬鹿になっちゃった回 https://t.co/KTNhPWDLQx とか好き OSS 観光名所を貼るスレ - ぽ靴な缶 https://t.co/ScIsJyGC0e — ksakahieki@恋垢 (@ksakahieki) 2023年12月2日 GitHub のRails リポジトリがハックされたやつも載せてほしい https://t.co/4KqXswesMX / “OSS 観光名所を貼るスレ - ぽ靴な缶” https://t.co/vbd1Nx698o — suginoy (@suginoy) 2023年12月2日 OSS 観光名所を貼るスレ - ぽ靴な缶 これも <a href="https://tech.a-listers.jp/2011/06/17/epic-fail-on-github/" target="_blank" rel="noopener nofollow">https://tech.a-listers.jp/2011/06/17/epic-fail-on-github/</a> 2023/12/03 00:33 OSS 観光名所を貼るスレ - ぽ靴な缶 個人的にはこれ→<a href="https://github.com/cocoa-mhlw/cocoa/issues/95" target="_blank" rel="noopener nofollow">https://github.com/cocoa-mhlw/cocoa/issues/95</a>「OSのプロキシ設定を無視したHTTP接続を行っている」 2023/12/03 01:34 おもしろかった。個人的にはUI LibraryのAnt Designで、クリスマスになると勝手にデザインが変わる時限爆弾を思い出した。https://t.co/QC92u9sa0L / “OSS 観光名所を貼るスレ - ぽ靴な缶” https://t.co/a3kEb8CzE3 — snagasawa (@snagasawa_) 2023年12月2日 弊社のリポジトリでは変数の横に*が10個付いたCのコード(ポインタのポインタの…って10回分)が発見されて話題になったことがあるhttps://t.co/PMdgMEqy3c — ぞりお (@__zorio__) 2023年12月3日 これは楽しいw/命名関係は色々意見があるよねぇ…/個人的には古いけど「membarrier()システムコール」の話が大好きw https://t.co/yBJF2NuIkL / 他39件のコメント https://t.co/1EtRLNGIF8 “OSS 観光名所を貼るスレ - ぽ靴な缶” (331 users) https://t.co/FJZlUX0fAO — wisboot (@wisboot) 2023年12月3日

  • ぽ靴な缶

    Google Cloud 認定 Professional Data Engineer 取りました

    やったー Google Cloud の主催する Google Cloud Innovators Gym Japan (G.I.G) というプログラムに参加して取りました。 Google Cloud を利用する企業を対象とした招待制のプログラムで、参加すると関連する Coursera コースへのアクセス、試験を受けるためのサポート、Google Cloud エンジニアの方によるハンズオンや質問できる機会が提供されます。 バッジ 以下の資格が対象。今回のプログラムは4月中頃に始まり、7月中頃までに Coursera のコースを終え合格報告をするスケジュール。お話を頂いて良い機会なのでチームの若者を誘って参加しました。 Professional Cloud Architect Professional Cloud Developer Professional Data Engineer pokutuna は公式ドキュメント読んで筋の良い手段を取ればいい、正直俺ならいつでも資格は取れる... という傲慢さを持っているわけだけど、なら取れよと思うのも当然の話、無免許で Google Cloud を触っている事実は覆せない。なら GW 予定もなんもねえし最速で取ってやるわいと、GW 中に PDE コースの Coursera を終え、記憶が揮発しないよう頭皮をキュッと絞めながら5月末に試験を受けた。 普段やってる範囲については良い再確認の機会になった。各プロダクトそれぞれのドキュメントを読みつつ、過去の経験や一般的なソフトウェアに対する感覚で色々判断しているわけだけど、Coursera の授業を聞くとまあそうなるよね間違ってなかったわとなるし、微妙に知らないことや使ってない機能の知識も補えた。あと同僚に説明する時も言語化しやすくなったと思う。普段使っていない Dataflow や BigTable はフムフムと授業を聞けた一方、Dataproc はモチベーション上がらなかったな。今から Spark や Hadoop を選択しない...という気持ちがある。Data Engineer でも ML の話はあるものの概念や手法の一般的な話なのでまあいける。再現率と適合率、どっちがどっちか毎回忘れるので覚えたけど、テスト勉強自体 10 年ぶりなので懐かしい感じがした。 印象に残ったのはコンピューティングとストレージの分離の話。 アーキテクチャの話として出てくるけど、クラウドやサーバレスの切り口にもなる話だった。この 2 つを分離できるなら一気にスケールできて、ボトルネックがネットワークに移る。分離できないアーキテクチャだったら2つセットの仮想マシン的な単位で借りないといけない、1台のキャパシティに気を揉むことになる。サーバーレス以前のアプリケーションはそうなりがちだし、要求が高い OLTP な DB だったりしてもそうなる、みたいな理解ができる。 そう考えると Spanner はめちゃすごいし、その後に演習で BigTable インスタンス作るけど、操作可能になるまでの速さにびっくりするのでうまく出来ているんだなと思う。 もう1つは、秘訣(The secret sauce) - How Google does Machine Learning で出てくる "自分で見たことがないデータは準備不足" という話。気に入ったところを引用する。 十分なデータが集まってない またはアクセスできない時点で MLについて話しても無意味です 実はデータがあるかもしれませんね 何年も記録し 別の部署が管理しているシステムに あるかもしれません でも実際に見たことはありません 私は自信を持って言います 自分で見たことがないデータは準備不足です それだけでなく 定期的にそのデータを確認して レポート作成や新たな発見をする人が 組織にいないなら つまり そのデータがすでに 価値を生み出していないなら データの保守に努力が 払われていない可能性が高く データが次第に廃れていきます これまで対話したクライアントの中で クリーンデータを集める労力を 過小評価しない人には 会ったことがありません 「思ったより簡単だった」と言う人はいません 多くの苦労や障害に直面するでしょう おっしゃる通りです、感動で泣ける。 これは ML Engineer の授業なんだけど、規定の 3 コース以外の Coursera にもアクセスさせてもらえるので見れた。ありがたいですね。 試験について 公式の模擬試験は初見 88% 正答だったので、まあ見直せば合格やろと思いつつ念のため Kindle で売ってた模擬問題集をやったりした。要件に応じてどのプロダクトを選ぶかとか、コスト最適化とか定番問題は色々ある。読みながら雑にまとめたメモはこれ、メモなので整理されてはいないけど助けになる人も居るでしょう。Processional Data Engineer - pokutuna 模擬問題集には、かなりの悪文があったり、その選択肢じゃ一意に決まらなくない? と思う問題もあった。商品レビューで低評価されているものの、ある意味かなり役に立ちました。Coursera だけで試験突撃してたら落ちてた可能性ある。で、こういう問題集なんですが... 真面目に作ってる人も居そうですし、言いがかりになると悪いんだけど... これ英語の書籍や海外コミュニティの問題を機械翻訳したやつだったり、公式模擬試験を更新のたびに集めたやつだったりしない? 俺が見たヤツはそういう感じが漂っている... 役には立ったし恩は感じるけど、宣伝したくはないという複雑な気分。 試験は大阪の Kryterion と提携するテストセンターで受けた。リモートも選べたけど、専用ソフト入れたり部屋を片付けて試験官に見せたりしたくないなと。行って受付したら、即ロッカーに私物全部入れて待っててくださいという感じだったのは予想外だった。試験開始時間を待ちながら携帯で見直す想定だったんだけど...もっとギリギリに行ってもよかった。試験は席ごとに衝立が置かれた学校の PC 教室のようなところで受ける。同じ部屋の受験者同士で受けてる試験は違っていて、待っている間の周囲の会話の感じだと、TOEFL や Microsoft Office の資格試験なんかも同時にやっているようだった。 あとこれは規約で共有を禁じられた試験内容にあたらないと思って書くんですが、環境が中華フォントで問題文が読みづらかった...理解するのに支障はないけど、ボタンラベルが 見直す になってるのは日本語表示環境じゃないでしょう。 認定証の検証 試験に合格すると、Accredibleで認定証とバッジ画像が発行される。 そんで認定証の存在がブロックチェーンに記録されてるらしいじゃないですか、しかも BTC。BigQuery に精通する Professional Data Engineer として、証明書の存在を UDF で検証しつつ bigquery-public-data.crypto_bitcoin.blocks の行を SELECT する SQL を披露するのが合格エントリに相応しい。 そう思ってマークルツリーの仕組みとか読んでみたけど、肝心のリーフとなる自分の証明書の SHA256 を得る方法が分からない。このドキュメントの "similar to ~" で濁されているところが知りたいんだけど... 一応 blockchain-certificates/cert-schemaを読んで、Accredible の blockchain data API から得られる JSON 中の credential_json_data を URDNA2015 & nquads で正規化したりしてみたんだけど、API のレスポンスに含まれるハッシュにならなかった。証明書と btc_anchor_branch からこのクエリの merkle_root を計算して SELECT してドヤ、という予定だったんだけど、興味が続かなくて諦めた。 SELECT * FROM `bigquery-public-data.crypto_bitcoin.blocks` WHERE merkle_root = "de49e548fe4fb7b8b01f263b101c87f08a3c384c9d0e6d873daa179378ae5376" AND timestamp_month = "2023-05-01" Open Badge の仕様は読んでみて、バッジの png 画像から URL を取り出すのは書けた。記事冒頭のバッジ画像から取り出せるよ。 badge.go · GitHub

  • ぽ靴な缶

    Google Cloud 版 Dataform と周辺リソースの図

    GCP 版 Dataform がついに GA になりましたね。同時に定期実行の仕組みも出て、一通りの機能が揃った感がある。いまこそ買収以前の SaaS 版(Legacy 版)から GCP 版に移行する時!! しかし GitHub リポジトリと連携する場合、登場人物が多くて難しくなっていると思う。 特に GCP に馴染みがなかったりデータ分析がメインの人は困りそう。公式ドキュメントには step by step で書いてあるものの、なぜ必要なのか分からないまま設定することになる。 なので全体像を図にしたり補足するという趣旨のエントリです。 Dataform とは Dataform とは...という話はしません。公式ドキュメントや世間のブログ記事を読もう。 Dataform を使うと、テーブル同士の依存に基づいて順番に SQL を実行してデータパイプラインを作ったり、依存関係を可視化したり、データセット名に suffix を付与してステージング環境を作ったりできる。 現状の Dataform でカバーしきれない複雑な要件、具体的には更新や変換にリアルタイム性が要求されたり、外部の依存やトリガーに基づくパイプラインなどでは Cloud Dataflow や Clodu Composer が必要になるけど、データウェアハウス実装のかなりの範囲をカバーするサービスです。 cloud.google.com Google Cloud のリソースとの関係 このあたりのドキュメントで登場する登場人物をまとめた。 Quickstart: Create and execute a SQL workflow  |  Dataform  |  Google Cloud Create a Dataform repository  |  Google Cloud Connect to a third-party Git repository  |  Dataform  |  Google Cloud Dataform と周辺リソースの関係 ① まず Dataform API を有効にして、コンソールから Dataform リポジトリを作る。 すると ② Dataform サービスアカウントが Cloud IAM に生えてくる。 service-{PROJECT_NUMBER}@gcp-sa-dataform.iam.gserviceaccount.com の形式。 IAM 一覧では、ユーザが作ったもの以外はデフォルトでは非表示なので、"Google 提供のロール付与を含める" をチェックするとよい。 ふくめる 重要なのは、Dataform はこのサービスアカウントの権限で動作するということ。 ③ GitHub に行き、Dataform のコードを保存するリポジトリを作る。 ④このリポジトリを GCP 側から操作するため Personal access token (PAT) を払い出す 今 GitHub には 2 種類の PAT がある。 personal access tokens (classic) fine-grained personal access token classic は以前からあるが、リポジトリ単位でのアクセス制御ができない。新しい fine-grained を使い ③ で作ったリポジトリのみ許可するのが良い。classic では、scope に repo を、fine-grained では Repository permissions で Contents: read and write を与えればよい。 ⑤ 再び GCP 側に戻り、Secret Manager でシークレットを作成し、④ で作成した PAT をバージョンとして保存する。 ⑥ シークレットの "権限" タブで、② の Dataform サービスアカウントに roles/secretmanager.secretAccessor ロールを付与して Dataform がこのトークンを利用できるようにする。 補足すると、ここでは個別のシークレットへのアクセス権を付与している。IAM コンソールの目立つボタンからロールを付与すると、プロジェクトレベルのアクセス権となり、一通りのシークレットにアクセスできる権限を付与することになるので注意。 これで Dataform コンソールでコードを書いて GitHub へ push できるようになった。 ⑦ Dataform を使う目的は BigQuery のテーブルを作成したり更新したりすることなので、IAM で Dataform サービスアカウントに BigQuery を操作する以下の権限を付与する。 BigQuery ジョブユーザー (roles/bigquery.jobUser) BigQuery データ編集者 (roles/bigquery.dataEditor) その他、別のプロジェクトのデータを参照したい場合は、そちらでも BigQuery データ閲覧者(roles/bigquery.dataViewer) を付与する。更新したいならデータ編集者ね。Dataform 実行プロジェクトと BigQuery リソースのプロジェクトは異なっていても構わない。 Google Spreadsheet など Google ドライブのデータを外部テーブルとして扱いたい場合は、該当のファイルを Dataform サービスアカウントに共有すればよい。 Spreadsheet をサービスアカウントに共有する (オプション) CI やその他のワークフローから実行する可能性があるなら、それ用のサービスアカウントを作っておくとよい。 ② のサービスアカウントは、GCP が管理するもので Service Agentとも呼ばれる。追加のロールを付与することはできるけど、ユーザーが成り代わったり認証情報を入手したりはできないので、Dataform コンソールの外から利用できない。 IAM での権限は Google グループに対しても付与できるので、Dataform サービスエージェントと、CI 用のサービスアカウントを所属させておいて、そのグループに対して BigQuery の権限を与えるようにしておくと、2 つのサービスアカウントそれぞれ与えなくて済むし権限が食い違うこともなくなる。 サービスアカウントを Google グループに所属させる cloud.google.com GitHub リポジトリと連携しなくても使える ここまで GitHub リポジトリと連携するつもりで書いていたけど、連携しなくても Dataform を使うことはできる。 リポジトリとしての便利さはほぼ得られない。2023-05-14 現在、HEAD にコミットするか戻すかどうか、Workspace の変更を main に push する操作だけできる。 ちょっと触ってみたいだけなら、連携部分は気にしないでいいと思う。必要になったら GitHub リポジトリと接続すればいい。Legacy 版と違って既にファイルのある GitHub リポジトリと連携することもできるし。 CI GitHub 連携をしたら GitHub Actions で CI を整備したいですね。 push したら compile に成功するかチェック & dry-run する main にマージしたら Dataform を実行する などするようにしています。 cloud.google.com CI で色々やる際の注意点として、ルートの package.json の依存は @dataform/core のみか、最小限にする必要がある。Dataform コンソールで SQLX をコンパイルする際に、バックグラウンドで npm install が走っているようだけど、依存が増えるとタイムアウトしてまともに使えなくなる。@dataform/cli が増えただけでダメ。 CI の中でだけインストールしたり $ npx -p @dataform/cli@latest dataform compile などしています。 Can't install certain devDependencies [264598563] - Visible to Public - Issue Tracker おまけ Dataform 関連だけ抜き出した Terraform、google-beta が要ります。 resources.tf variable "project" { type = string } variable "region" { type = string default = "asia-northeast1" } variable "dataform_repository_url" { type = string } variable "dataform_default_branch" { type = string default = "main" } data "google_project" "this" { project_id = var.project } resource "google_secret_manager_secret" "dataform_repository_token" { secret_id = "dataform_thirdparty_repository_token" replication { automatic = true } } resource "google_secret_manager_secret_version" "dataform_repository_token" { secret = google_secret_manager_secret.dataform_repository_token.id secret_data = "******" } # secret が state に書かれてしまうので、普段は手でコンソールから secret と version を作って # secret は terraform import、 version は data リソースで参照、みたいにしている # # data "google_secret_manager_secret" "dataform_repository_token" { # secret = google_secret_manager_secret.dataform_repository_token.id # } resource "google_dataform_repository" "dataform" { provider = google-beta name = "my-dataform-repository" region = var.region git_remote_settings { url = var.dataform_repository_url default_branch = var.dataform_default_branch authentication_token_secret_version = google_secret_manager_secret_version.dataform_repository_token.id } } # Dataform Service Agent へのロール付与 locals { dataform_agent_member = "serviceAccount:service-${data.google_project.this.number}@gcp-sa-dataform.iam.gserviceaccount.com" } resource "google_project_iam_member" "dataform_agent_roles" { for_each = toset([ "roles/bigquery.dataEditor", "roles/bigquery.jobUser", "roles/dataform.editor", "roles/dataform.serviceAgent", ]) project = var.project role = each.value member = local.dataform_agent_member depends_on = [ # Dataform Service Agent は最初の repository が作成された後に作られる google_dataform_repository.dataform ] } resource "google_secret_manager_secret_iam_member" "dataform_repository_token" { secret_id = google_secret_manager_secret.dataform_repository_token.secret_id role = "roles/secretmanager.secretAccessor" member = local.dataform_agent_member depends_on = [ google_dataform_repository.dataform ] } # CI などから Dataform を実行するためのサービスアカウント resource "google_service_account" "dataform" { account_id = "dataform" display_name = "dataform" description = "Dataform 実行用サービスアカウント" } resource "google_project_iam_member" "dataform_sa_roles" { for_each = toset([ "roles/bigquery.dataEditor", "roles/bigquery.jobUser", "roles/dataform.editor", ]) project = var.project role = each.value member = google_service_account.dataform.member } おわりに Dataform が買収されて進化が止まっている間にライバルの dbt が普及してしまった感がありますが、巻き返してほしいですね。 Google Cloud 組み込みだし、BigQuery を DWH として使っていたらすぐ使い始められるし、無料だし dbt Cloud のようにユーザー数課金でもない、第一の選択肢になると思います。 気が向いたら、定期実行とその通知について書こうと思います。

  • ぽ靴な缶

    Slack チャンネルのロボット帝国化を防ぐ feed-pruning-proxy

    この記事は はてなエンジニア Advent Calendar 2022 2日目の記事です。 みなさんは Slack の RSS アプリ を使っていますか? /feed subscribe FEED_URL で RSS や Atom フィードをチャンネルに流すことができます。 Slack に RSS フィードを追加する | Slack これを使って各種リリースノートやニュースサイトの新着をいろんなチャンネルに流しています。Slack をお使いの皆様もきっとそうしているでしょう。 フィードによって技術の最前線をキャッチアップでき、供給された話題は参加者同士の活発な議論を産む。学習とコラボレーションが同時に促進される素晴らしい機能と言えますね。 . . . 本当か??? 例えば BigQuery のリリースノートを流すとこうなる!! 激流 これ 5 記事あるわけじゃないからな。 こんなフィードをチャンネルに流していると、いつ開いてもフィードしか見えない。 そうして人々は言葉を発しなくなる。 そうやって生まれた自動的な通知ばかりで人が話さなくなったチャンネルをロボット帝国と呼んでいます。人類は機械に支配されたのである。 展開オプション 当然知っているけど、Slack には展開オプションがあって、受け手側で展開を抑制することもできる。 でも全く展開してほしくないわけじゃないのよ、普段の会話では展開してくれるのは便利だし。 展開オプション ロボット帝国に対抗するために生まれた feed-pruning-proxy そんなチャンネルに人間性を取り戻すため pokutuna/feed-pruning-proxy を開発しました。 これはクエリパラメータに与えた URL のフィードの内容を加工して返すアプリケーションです。 いくつかの機能がある。 /p?feed={url} (デフォルト) フィード中の各エントリの本文部分を削除します。 RSS なら description, Atom なら summary と content 記事の URL やタイトルは流れるので、それだけ Slack が展開することに期待します フィードの本文と展開される URL の内容が重複するようなフィードに対して、2回も言わなくていいよという時に使う。 /p?feed={url}&diet (diet モード) フィード中の各エントリの本文部分のマークアップを削除します。 リンクの展開を抑制しつつ本文を出力したい時に使います。 Slack の展開結果が 何もない or 画像だけ のような、何か言ってよというページに対して使う。 こうして得た URL を /feed で購読することで、たかだか1つ展開されるちょうどよい出力がチャンネルに流れるようになります。 実際に記事を読んでるのか そういう気持ちになることもありませんか。それも解決します /p?feed={url}&org={str}&channel={str} とすると これで実際にフィードから記事を読みに行っているのか計測できるようになり、このフィード誰も見てないし remove しましょう、という話ができるようになる。 このログを BigQuery に流し込むと集計や可視化も簡単にできて、みんなが注目した記事とかが分かって楽しいですね。 ご利用頂けます これを GAE にデプロイしておきました。こちらからご利用いただけます。 https://feed-pruning-proxy.an.r.appspot.com/ 迷惑がかかるような使い方をされていたり、金がかかるな〜思ったら予告なく止めるかもしれません。 App Engine または Cloud Run へのデプロイ なのでぜひ自分の GCP プロジェクトにデプロイしてみてください。 App Engine へのデプロイは $ gcloud app deploy でできます。エッジキャッシュもあるし、こういうちょっとしたアプリケーションを公開するのに大変便利ですね。 blog.pokutuna.com また、Cloud Run にデプロイできるボタンを README に置いておきました。押すと Cloud Shell が開いて Cloud Run にデプロイできます。 これを使っています github.com さあロボット帝国に抗い、人間の輝きを取り戻しましょう。 はてなエンジニア Advent Calendar 2022 2日目の記事でした。 昨日は id:arthur-1 さんの Advent Calendar を Mackerel で監視する 〜新卒の暮らし方を添えて〜』 でした 明日は id:mizdra さんです。

  • ぽ靴な缶

    なぜ今も Google App Engine を選ぶのか

    Google Cloud で何かアプリケーションを動かしたい時、いつも App Engine (GAE) を第一の選択肢として挙げています。 なのにみ〜んな Cloud Run に行ってしまう。なぜなのか?? 確かに Cloud Run のほうが新しくて公式に露出が多いし、GAE はこういうランディングページからの言及も消えているので無理もない。Google Cloud 的にもあんまり使って欲しくない雰囲気が漂っている。 cloud.google.com App Engine は GCP 最初期からあるサービスで今年で 14 年目になるらしい。 Google App Engine 単体で出ていて、他のサービスが続いて Google Cloud Platform になったような気がする1。 そんな歴史あるサービスだとレガシー感が漂っていそうなものだけど、全くそんなことはない。 2019 年の 2nd gen 化から改めて使ってみたところ、圧倒的に良くなっているし、今も一線で使えるサーバレス実行環境である。 ポートフォリオサイトの https://pokutuna.com/ も GAE だし、仕事でも社内用の小さなアプリケーションから、多少トラフィックのある API サーバーまで GAE でリリースしてきた。 アプリケーション実行環境の選択肢は色々増えたものの、今でも GAE のほうが楽に安くアプリケーションを構築できる状況や要件はよくある。そんな GAE のいいところや GAE が便利な状況について書いておきたい。 静的ファイルを配れる & エッジキャッシュが使える GAE では、静的ファイルのパスを app.yaml で指定することで静的ファイルを Google のエッジサーバーでキャッシュさせつつ配れる。アプリケーションからのレスポンスでは Cache-Control: public, max-age=3600 などヘッダに含めることでキャッシュさせられる。 アプリケーションの手前にリバースプロキシを置いて静的ファイルを返す構成はよくあるが、GAE は単体でそれ相当のことができる。小規模なアプリケーションでとてもありがたい。手動のキャッシュの破棄はできないが、設定不要の CDN が付いているのに等しい。 GAE がこの機能を持つのは、静的ファイルを返すことは Web アプリケーションの通常のユースケースだからだろう。 どちらも HTTP エンドポイントを実行するサービスだけど、GAE がユーザ向けアプリケーションを公開することに重心を置いているのに対し、Cloud Run はもっと広く Pub/Sub を受けたりジョブを実行したり非同期システムのランタイムを志向しているので、Cloud Run がエッジキャッシュをサポートしていないのもまあ納得できる。 Cloud Run で静的ファイル返したい場合 手前に Cloud Load Balancing を置いて Cloud CDN を有効にする Firebase Hosting で静的ファイルを配りつつ特定のパスを Cloud Run に向ける 別に Cloud Storage に上げて公開して URL を返す 諦めて Cloud Run のアプリケーション内から返す などが考えられる。 1 つ目の、手前に Load Balancing を置いて Cloud CDN を使うのが素直な構成だと思うけど、Load Balancing を立てているだけで月数十ドルかかる。事業でサービスを公開するなら安いコストだけど、個人開発や社内向けの小さなアプリケーションだと地味に払いたくないコストである。 費用を意識するならコンポーネントは増えるがここだけ Firebase Hosting を使うのが良いと思う。 Identity-Aware Proxy (IAP) が Load Balancing 無しに使える IAP を使うと、アプリケーションに手を加えず簡単に Google Workspace ドメインや、特定の Google アカウントに対してのみアプリケーションを公開できる。管理画面や、社内用アプリケーションを作る際によく利用する。 Cloud Run や GKE で IAP を使うためには、Cloud Load Balancing が必要なのだけど、GAE だけは単体で IAP を挟むことができる。特に社内向けアプリケーションは、営業時間中にまばらにトラフィックがあるだけなのに LB 立て続けるのはもったいない。GAE すればコストがタダに近くなる。 cloud.google.com プロジェクトの初めのうちはプロトタイプを IAP かけた GAE で開発しつつ、一般公開前に Cloud Load Balancing を立ててバックエンドサービスに GAE を指定して将来の構成の変更に対応しやすくする、というのもいいでしょう(ちょうど最近やりました)。 今は App Engine にロックインされない かつては、ローカルの開発時に dev_appserver.py とかいうよくわからんスクリプトを使う必要があったり、外部に HTTP リクエストを送るのに専用の urlfetch ライブラリを使う必要があったり、ライブラリを自由に入れられないので自分でアップロードしてインポートパスを通したりする必要があった。ロックインされるし、開発体験が良くなかった。 2nd gen になってからこれらの制約は無くなった。ふつうに書いた Web アプリケーションがそのまま動く。 1st gen は独自のサンドボックスでユーザのアプリケーションを分離していたのと、ユーザ認証からデータストア、タスクキューまで付いたオールインワンのアプリケーション実行環境として提供されていたのもあって、専用ライブラリを使ってね、としていたのだと思う。 2nd gen では、それら GAE にバンドルされていたサービスは各 Google Cloud プロダクトを利用して実装する形になった2。App Engine 特有の実装も不要になり、脱出も容易、つまり、安心して使えます。 cloud.google.com ランタイム選択フローチャート かつてこういう図が公式ドキュメントにあった。 (引用) Which serverless compute platform is right for you? の図 Choosing a Serverless Option  |  Serverless Guide  |  Google Cloud (Internet Archive) これをたどると、大半のユースケースで App Engine に辿り着かない? 僕はまず GAE で動かせないか検討して、言語がサポートされていないとか、追加で何かインストールしないといけない要件(Image Magick 要るとか)がある場合に Cloud Run を検討する、という感じでやっている。 過去には、やや複雑化してきた Cloud Function を GAE に置き換えたりもした。GAE は 0 台までダウンスケールできるし起動も早いし、新しいバージョンをリリースする際に段階的にトラフィックを移したり、前のバージョンに戻したりも楽ちん。Cloud Run でもよいけど、Cloud Functions で出来ていた程度のもののイメージを管理したくないという判断もあった。Cloud Functions gen2 はガワだけで中身は Cloud Run なので、今なら Run にするかな。 繰り返しになるけど、LB もいらず IAP もかけられるので、GAE はプロトタイプの開発にも向いていると思う。 まとめ GAE の楽さや安上がりな点について紹介しました。 こんなアプリケーションに集中できるいいプロダクトなのに公式の案内から消えていきつつある!! みんなが GAE でケチりながら激安アプリケーションをホストすると Google が儲からないので隠されているのだと思う。 このエントリで GAE が選択肢に上がるとうれしいです。 App Engine の中心的な考え方であるサーバーレス、サーバー管理不要、イベントドリブン プログラミング、リソースの使用量に応じた料金などは 10 年前から一貫しており、現在も当時と同様に当を得ています。 誕生から 10 年、App Engine の歩みを振り返って | Google Cloud 公式ブログ これかっこいい、おっしゃる通りです 関連エントリ blog.pokutuna.com blog.pokutuna.com Wikipedia(en) の Google Cloud Platform ページの最初の履歴は 2014 年で、記述を見るたぶん合ってるのではないか https://en.wikipedia.org/w/index.php?title=Google_Cloud_Platform&oldid=602909799↩ Google Cloud が提供していないものもあるけど...↩

  • ぽ靴な缶

    2022-10 の Cloud Storage 料金改定に伴い GCR から Artifact Registry へ移行する

    Google Cloud で運用しているサービスの Cloud Storage 費用が10月の料金改定から爆増していた。 Cloud Storage 費用(オレンジ部分)が増加 料金改定のタイミングで Cloud Storage のマルチリージョンからマルチリージョン内のリージョンへの転送費用が無料じゃなくなっていた。 Docker イメージの転送費用によるものであれば、Container Registry から Artifact Registry へ移行することでこの費用は無にできる。 cloud.google.com 無料条件がなくなった Google Cloud 内の下り(外向き)ネットワーク費用を見る。 Internet Archive に残っている過去の料金表(2022-05-01)には以下の記述があった。 マルチリージョンにある Cloud Storage バケットからある 1 つのリージョンにある別の Google Cloud サービスへのデータの移動で、両方のロケーションが同じ大陸にある。 無料 現行は、この無料条件がなくなっているうえに、 $0.08/GB とまずまず高めの値段設定になった。 同じ大陸内の異なるロケーション間でデータを移動する場合、転送元バケットは ASIA マルチリージョンに配置され、上記の無料ケースのいずれも適用されない。 $0.08/GB cloud.google.com Container Registry (GCR) のコンテナイメージは Cloud Storage のマルチリージョンバケットに保存され、イメージを利用する実行環境は何らかのリージョンにあるので、この条件にあたってしまう。 今まではイメージと実行環境のロケーションを合わせていれば無料で使えたが1、一通りマルチリージョンバケットからの転送に費用がかかるようになってしまった現在はもう無料で使うことはできない!! asia ほどの費用にはならないが、gcr.io から us 内への転送も $0.02/GB と、無料ではなくなっている。 Artifact Registry を使う Container Registry (GCR) より後に公開された Artifact Registry。 Maven や npm モジュールなどもホストできる。 cloud.google.com 移行するモチベーションは特になかったけど、今回の費用改定で明らかにメリットが生まれてしまった。 Artifact Registry はアーティファクトを保存するリポジトリのロケーションを選ぶことができる。実行環境と同じロケーションにイメージを置くことで、Cloud Storage のネットワーク費用を無料にすることができる!! 移行する作業は特に難しくなく、ドキュメントで移行について案内されている。 cloud.google.com アクセス権限周りに大きな変更があったが、困るようなことはなかった。 GCR 時代のアクセスコントロールは Cloud Storage の IAM ロールでやる感じで、おおざっぱだし分かりづらかったけど、Artifact Registry ではそれ用のロールが設けられプロジェクト単位でも個別のリポジトリに対しても権限を設定できる。 実際の作業としては、API を有効にし、Artifact Registry にリポジトリを作って、GCR に置いてあるイメージを Artifact Registry Registry に上げなおして、k8s manifest やデプロイコマンドなど各所の image 指定を更新する程度でした。 これでグラフの右端のように、また Cloud Storage 費用を無にできたわけです。 今回の値上げといい、ドキュメントの記述といい、かなり Artifact Registry への移行を促してる感ありますね。 Container Registry の進化形である Artifact Registry は、 https://cloud.google.com/artifact-registry?hl=ja Container Registry は引き続き使用可能で、Google Enterprise API としてサポートされていますが、新機能は Artifact Registry でのみ利用可能です。Container Registry には、重要なセキュリティ修正のみ与えられます。 https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr Google Cloud のドキュメント中の "大陸" (continent に対する訳) って独特の概念だよね、ASIA マルチリージョンの各所は海で隔てられている(台湾, 香港, 東京, ムンバイ, ...)2ものの、同じ文脈で大陸として出てくる "US" や "EU" と同じ扱いであったりもするわけで。でもある日 ASIA は大陸じゃありませーんと言われてもしょうがない気もするし。 https://blog.pokutuna.com/entry/gke-autopilot-storage-egress↩ https://cloud.google.com/storage/docs/locations#available-locations↩

  • ぽ靴な缶

    gcloud の configurations を切り替える

    前回の記事では --project を毎回渡せという主張を展開していたけど切り替える話。 blog.pokutuna.com gcloud コマンドには構成を管理するサブコマンド gcloud config configurations がある。管理するプロジェクトが多くない場合は、カレントプロジェクトを設定しつつ切り替える運用でもよいのではないでしょうか。 また、複数の Google アカウントを切り替える場合も configuration を作って切り替えるのがいい。カレントプロジェクトは設定しない派だけど、個人の @gmail.com と勤務先の Google Workspace のログイン状態を切り替えるのに使ってる。 ちなみに configurations を切り替えても ADC はそのままで、最後に gcloud auth application-default login した時点の認証情報から変わらないのが注意ポイント。 gcloud config configurations Cloud SDK 構成の管理 | Cloud SDK のドキュメント | Google Cloud 触ってみないと微妙に分かりづらいけど、Google アカウントやカレントプロジェクトなど一連の設定を 1 つのエントリとしてまるっと切り替えることができる。 "プロジェクトを切り替えることができる" と説明されていたりするけど、Google アカウントを含む一連の構成を切り替えると思っておかないと、 gcloud config set project でプロジェクトを切り替えたり、ログインし直したりしているとよく分からなくなる。 プロジェクトを切り替えるには、同じ Google アカウントでログインした複数の構成を作って、別々のカレントプロジェクトを設定しておいて、それらを切り替えるという感じ。 # configuration の一覧 $ gcloud config configurations list # configuration を作る & 同時にその設定名がアクティブになる $ gcloud config configurations create NAME # configuration に設定する $ gcloud init # 最初から $ gcloud auth login --project=PROJECT_ID # ログインしてプロジェクト ID 設定する $ gcloud config set project PROJECT_ID # プロジェクト ID だけ設定する $ gcloud config set compute/region REGION # region $ gcloud config set comute/zone ZONE # zone # NAME の設定に切り替える $ gcloud config configurations activate NAME 例のように、region や zone も保存しておけるので、Compute Engine などこれらの引数を要求するコマンドをよく使うなら、設定してあるとちょっと楽になる。 gcloud config に設定できるもの 先に挙げたものが config に設定できるものとしてメジャーだけど、他にもいろんな設定を保存できるし、configuration で切り替えられる。 例えば以下のように設定しておくと、Cloud Functions に新しい関数をデプロイする際に region を省略しても asia-northeast1 になる。 $ gcloud config set functions/region asia-northeast1 設定可能な項目はドキュメントにちゃんとまとまってある。 gcloud config | Google Cloud CLI Documentation あるいは json や yaml で出力してみると雰囲気が分かっておもしろい。 $ gcloud config configurations list --format=json accessibility/screen_reader を true に設定すると gcloud の出力がスクリーンリーダーフレンドリーになったり、core/log_http すると gcloud の API リクエストとレスポンスが出力されたりして面白いですね。 fzf や peco で切り替える よくあるやつ。fzf でも peco でも動くので読み替える。 gcloud-switch() { local selected=$( gcloud config configurations list --format='table[no-heading](is_active.yesno(yes="[x]",no="[_]"), name, properties.core.account, properties.core.project.yesno(no="(unset)"))' \ | fzf --select-1 --query="$1" \ | awk '{print $2}' ) if [ -n "$selected" ]; then gcloud config configurations activate $selected fi } gcloud にはグローバルな `--format=NAME[ATTRIBUTES](PROJECTION) オプションがあって、単体で出力をかなり加工できる。他のツールと組み合わせるときに使うとかわいいですね。 gcloud topic formats | Google Cloud CLI Documentation gcloud topic projections | Google Cloud CLI Documentation あるいは direnv を使っている場合は CLOUDSDK_ACTIVE_CONFIG_NAME 環境変数で切り替えることもできる。チームで configuration 名をプロジェクト名にしてリポジトリに入れたりするのもよいかもしれません。 Cloud SDK 構成の管理 | Cloud SDK のドキュメント | Google Cloud

  • ぽ靴な缶

    gcloud にカレントプロジェクトを設定しない派

    gcloud CLI にカレントプロジェクトをなるべく持たせないようにして暮らしている。 gcloud はデフォルトでカレントプロジェクトのリソースを操作する。操作するプロジェクトが 1 つなら良いけど、仕事でも遊びでもいくつもの GCP プロジェクトを扱っているので、うっかり異なるプロジェクトのリソースを操作してしまったり、意図しないプロジェクトに費用が計上されてしまうのが嫌だから。 カレントプロジェクトは設定しないようにして、gcloud を使う時は都度 --project=PROJECT_ID で渡すようにしている。 # カレントプロジェクトを確認するには以下のコマンドなど $ gcloud config get-value project $ gcloud config list # カレントプロジェクトの設定を消す $ gcloud config unset project ローカルの ADC の quota project 忘れられがちだけど、ローカルの Application Default Credentials にもカレントプロジェクトに相当する "quota project" がある。 ADC についてはこちら blog.pokutuna.com ADC の quota project は、gcloud auth application-default login した時点のカレントプロジェクトが設定される。 ~/.config/gcloud/application_default_credentials.json を見ると分かるし、ログイン時のメッセージにも出てくる。 Credentials saved to file: [/Users/pokutuna/.config/gcloud/application_default_credentials.json] These credentials will be used by any library that requests Application Default Credentials (ADC). Quota project "pokutuna-playground" was added to ADC which can be used by Google client libraries for billing and quota. Note that some services may still bill the project owning the resource. 普段からカレントプロジェクトを設定しないようにしていると気にしなくて良いが、unset したり切り替えたりしていると gcloud のカレントプロジェクトと ADC の quota project が異なる状態になるのがややこしい。 なのでこれも設定しないようにしている。 カレントプロジェクトを ADC に伝播させたくない場合は ADC ログイン時に --disable-quota-project オプションを使う。 $ gcloud auth application-default login --disable-quota-project ADC に quota project を設定しない場合、以下のような警告を見ることになるけど、アプリケーションコードからプロジェクト ID を与えればよいので気にしない。 WARNING: Cannot find a quota project to add to ADC. You might receive a "quota exceeded" or "API not enabled" error. Run $ gcloud auth application-default set-quota-project to add a quota project. ADC にプロジェクト ID を持たせない暮らし ADC に quota project を設定しない場合、アプリケーションコード中にプロジェクトIDが登場することになるけど、意図しないプロジェクトを操作してしまう危険を避けることを優先している。 認証情報はメンドイので ADC に解決してほしいが、プロジェクト ID まで暗黙に解決したいことはほぼないし、複数のプロジェクトで同じコードを実行する場合でも、設定や環境変数などでアプリケーションに伝えればいいという考え。 GCP 上の実行環境でも、実行環境とプロジェクト ID が異なってないなら問題はない。 Node Google Cloud の各種プロダクトに用意されたクライアントライブラリはコンストラクタに渡せばいい。 // Imports the Google Cloud client library const {BigQuery} = require('@google-cloud/bigquery'); const client = new BigQuery({ projectId: "<PROJECT_ID>" }); Spreadsheet など、Google Cloud 感ないものは GoogleAuth に渡す。Spreadsheet や Calendar なども API を有効にしたり使用量を管理するために Google Cloud プロジェクトが必要。 googleapis/google-api-nodejs-client import { google } from "googleapis"; const auth = new google.auth.GoogleAuth({ projectId: "<PROJECT_ID>", scopes: [ "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/spreadsheets.readonly", ], }); const sheets = google.sheets({ version: "v4", auth }); Node の場合、明に指定しない場合は google-auth-library がプロジェクト ID を解決しようとする。その過程で GCLOUD_PROJECT や GOOGLE_CLOUD_PROJECT 環境変数を参照したり、gcloud のカレントプロジェクトを参照したりする(歴史的経緯だろうけど、この挙動が嫌だなあ)。 Go Go でも Google Cloud 系のクライアントライブラリでは素直に渡せばいい。 googleapis/google-cloud-go import ( "context" "cloud.google.com/go/bigquery" ) func main() { ctx := context.Background() client, err := bigquery.NewClient(ctx, "<PROJECT_ID>") ... } Google Cloud 感のないものは google.golang.org/api を使うことになるが、こちらは option.WithQuotaProject() を使う。google.golang.org/api 以下でほぼすべての Google の API を叩けるので、Cloud API もこちらの方法で叩ける。 googleapis/google-api-go-client import ( "context" "google.golang.org/api/option" "google.golang.org/api/sheets/v4" ) func main() { ctx := context.Background() client, err := sheets.NewService(ctx, option.WithQuotaProject("<PROJECT_ID>")) ... } まとめ いろんなプロジェクトを触る場合は gcloud にカレントプロジェクトを設定しないのをおすすめしている ローカルの ADC も quota project があり、ログイン時のカレントプロジェクトが引き継がれる、これも設定しないのがいい アプリケーションコードでプロジェクト ID を明に指定すればいい blog.pokutuna.com

  • ぽ靴な缶

    GCP IAM ロールの持つ権限を比較するテク

    メンバーやサービスアカウントの権限を考える際に、ロールの持つ権限を比較したいことがしばしばある。そういう時は gcloud と diff を使うことで比較できるという素朴なテク。 ロールと権限 ロール(role)は roles/{roleName}, roles/{service}.{roleName} などで表され、許可されている操作を表す権限(permission)の集合である。 例えば BigQuery データ閲覧者 (roles/bigquery.dataViewer) は、以下の permission を持つ。 bigquery.datasets.get bigquery.datasets.getIamPolicy bigquery.models.export bigquery.models.getData bigquery.models.getMetadata bigquery.models.list bigquery.routines.get bigquery.routines.list bigquery.tables.createSnapshot bigquery.tables.export bigquery.tables.get bigquery.tables.getData bigquery.tables.getIamPolicy bigquery.tables.list resourcemanager.projects.get resourcemanager.projects.list cloud.google.com ロールの比較 個別のロールと権限について確認したいときは以下のドキュメントを見る、GCP 屈指の縦に長いページ role から permission Understanding roles | IAM Documentation | Google Cloud permission からそれを持つ role IAM permissions reference | IAM Documentation | Google Cloud role をいじっていると以下のような疑問が湧いてくることがある。 roles/bigquery.dataViewer と roles/bigquery.metadataViewer ってテーブルのデータ読める以外に何が違うんだっけ? roles/browser と roles/resourcemanager.folderViewer ってどう違うんだっけ? roles/editor は強い権限だけど、意外と SecretManager で出来ない操作あった気がする 上のドキュメントを行ったり来たりしてもいいけど、* でサービス内の個別の permission が省略されていたりするのでいまいち分からないし大変。 diff で比較する そういう時は gcloud コマンドで role の permission を得つつ、diff で比較するとよい $ gcloud iam roles describe ROLE で権限のリストが得られるので、これを diff -y で左右に並べる。 roles/bigquery.dataViewer と roles/bigquery.metadataViewer の違いは、 $ diff -y -W80 <(gcloud iam roles describe roles/bigquery.dataViewer) <(gcloud iam roles describe roles/bigquery.metadataViewer) description: Access to view datasets | description: Access to view table and etag: AA== etag: AA== includedPermissions: includedPermissions: - bigquery.datasets.get - bigquery.datasets.get - bigquery.datasets.getIamPolicy - bigquery.datasets.getIamPolicy - bigquery.models.export < - bigquery.models.getData < - bigquery.models.getMetadata - bigquery.models.getMetadata - bigquery.models.list - bigquery.models.list - bigquery.routines.get - bigquery.routines.get - bigquery.routines.list - bigquery.routines.list - bigquery.tables.createSnapshot < - bigquery.tables.export < - bigquery.tables.get - bigquery.tables.get - bigquery.tables.getData < - bigquery.tables.getIamPolicy - bigquery.tables.getIamPolicy - bigquery.tables.list - bigquery.tables.list - resourcemanager.projects.get - resourcemanager.projects.get - resourcemanager.projects.list - resourcemanager.projects.list name: roles/bigquery.dataViewer | name: roles/bigquery.metadataViewer stage: GA stage: GA title: BigQuery Data Viewer | title: BigQuery Metadata Viewer ほうほう、roles/bigquery.dataViewer はテーブルやモデルのスナップショットやエクスポートも取れるんですね。 includedPermissions 以下だけ欲しいなら --format オプションで中身だけ取ることもできる。 --format='value[delimiter="\\n"](includedPermissions)' gcloud の format オプションについてはこちら。 roles/browser と roles/resourcemanager.folderViewer の違いは、 $ diff -y \ <(gcloud iam roles describe roles/browser --format='value[delimiter="\\n"](includedPermissions)') \ <(gcloud iam roles describe roles/resourcemanager.folderViewer --format='value[delimiter="\\n"](includedPermissions)') > orgpolicy.constraints.list > orgpolicy.policies.list > orgpolicy.policy.get resourcemanager.folders.get resourcemanager.folders.get resourcemanager.folders.list resourcemanager.folders.list resourcemanager.organizations.get < resourcemanager.projects.get resourcemanager.projects.get resourcemanager.projects.getIamPolicy < resourcemanager.projects.list resourcemanager.projects.list フムフム。 多くの permission を持つ権限なら比較したい部分で grep すればいいですね。 roles/editor のうち、SecretManager で、roles/secretmanager.admin より弱いのは、 $ diff -y <(gcloud iam roles describe roles/editor | grep secretmanager) <(gcloud iam roles describe roles/secretmanager.admin | grep secretmanager) - secretmanager.locations.get - secretmanager.locations.get - secretmanager.locations.list - secretmanager.locations.list - secretmanager.secrets.create - secretmanager.secrets.create - secretmanager.secrets.delete - secretmanager.secrets.delete - secretmanager.secrets.get - secretmanager.secrets.get - secretmanager.secrets.getIamPolicy - secretmanager.secrets.getIamPolicy - secretmanager.secrets.list - secretmanager.secrets.list > - secretmanager.secrets.setIamPolicy - secretmanager.secrets.update - secretmanager.secrets.update > - secretmanager.versions.access - secretmanager.versions.add - secretmanager.versions.add - secretmanager.versions.destroy - secretmanager.versions.destroy - secretmanager.versions.disable - secretmanager.versions.disable - secretmanager.versions.enable - secretmanager.versions.enable - secretmanager.versions.get - secretmanager.versions.get - secretmanager.versions.list - secretmanager.versions.list > name: roles/secretmanager.admin roles/editor でも、secret に IAM Policy を設定することと、実際の version の読み取りができないのだな〜ということが分かる。 gcloud と diff を使うとこういう感じで比較できます。 適切なロールを選ぶとともに、IAM の推奨事項を見て絞ったりできるとよりよいですね。 cloud.google.com