GitHubと併せて使うと便利なツール

Monaco Markdown Editor For GitHub

GitHubでMarkdownを書くときにテキストエリアがVS Codeみたいになるブラウザ拡張

chrome.google.com

機能としては

  • Markdownとコードスニペットのシンタックスハイライト
  • Tabでインデント、Shift+Tabでインデントの戻し
  • マルチカーソル
  • F11でフルスクリーン
    • フルスクリーンモードでは、十分な領域があればプレビューを表示
  • etc

github1s

GitHubのリポジトリのURLに1sを追加するだけで、VS Codeでリポジトリを読むことができるサービス

例えば、VS Codeのリポジトリ

https://github.com/microsoft/vscode

を見たい場合は、

https://github1s.com/microsoft/vscode

を開くだけ。

なんだけど、そのためのブラウザ拡張を入れておくとさらに便利。 chrome.google.com

githubbox

GitHubのリポジトリのURLにboxを追加するだけで、CodeSandboxでリポジトリを読むことができるサービス

例えば、 https://github.com/dferber90/githubbox

を見たい場合は、

https://githubbox.com/dferber90/githubbox

を開くだけ。

わかばちゃんと学ぶ Git使い方入門

わかばちゃんと学ぶ Git使い方入門

「ソフトウェア開発の話題で業界での6年を経て私の考えが変わったもの」を読んで

Software development topics I've changed my mind on after 6 years in the industry」という興味深い記事が盛り上がっていたので、自分の感想を少々書いて見ようと思います。

自分の感想の前に参考までに意訳を掲載しますが、正確には原文を参照してもらえると幸いです。

記事の意訳

考えが変わったもの

かつての私であれば反論したであろうが今は信じていること

  • 経験のレベルが様々な人からなるチームで働く時には、型付言語の方が良い
  • スタンドアップは、新人を見守るのに実に有益である
  • スプリントレトロスペクティブは、本当に進路を修正するためであり、かつ、「アジャイル」「スクラムマスター」とかいうやつが行う時間の無駄遣いのためでない限り、やる意味がある
  • ソフトウェアアーキテクチャーは、おそらく他の何よりも重要である。良い抽象化のクソ実装は、コードベースにとって、実質的には害にならない。ダメな抽象化やレイヤーの欠落は、全てをゴミにしてしまう
  • Javaは言語としてそんなに悪くない
  • クレバーなコードは普通、良いコードではない。明快さが他のどんなことにも勝る
  • どんなパラダイムにおいてもダメなコードは書かれる
  • いわゆる「ベストプラクティス」は、状況によるし、幅広く適用可能ではない。盲目的に従うのはバカである。
  • 必要もないのにスケーラブルなシステムを設計するのはダメなエンジニアである
  • 静的解析は役に立つ
  • DRYは、一つの限定的な問題の予防にまつわるものであって、それ自体が最終目的ではない
  • 一般的に、RDBMS > NoSql
  • 関数型プログラミングは、ツールの一つであって、万能薬ではない

途中で取り上げたもの

  • YAGNI、SOLID、DRY。この順序で。
  • 鉛筆と紙は、とても良いプログラミングツールである
  • 現実的であるために綺麗であることを諦めるのは通常は良い判断である
  • テクノロジーをさらに追加するのが良い判断であることは稀である
  • 顧客と直接話すことは、常に、問題についてより多くのことをより少ない時間でより正確に明らかにする
  • 「スケーラブル」という言葉は、ソフトウェアエンジニアの精神に異常をきたす不思議な力がある。その言葉を発するだけで、エンジニアを狂乱状態にさせることがある。理不尽な行為もこの言葉を使うと正当化される
  • 「エンジニア」と呼ばれているにも関わらず、ほとんどの判断は、支えとなる分析やデータや数値を持たないカルトである
  • 100を超える面接を実施した後で:面接は全くうまくいかない。さらに、面接をどう改善すべきか全然分からない

昔からの考えで変わっていないもの

  • コードスタイルやlintルールなど細かいことを強調する人は変な奴である
  • コードカバレッジは全くもってコードの品質と関係がない
  • モノリスはほとんどの状況でかなり良い
  • TDD原理主義者は、最悪である。彼らのか細くてちっちゃな心は他のワークフローの存在を処理することができない

自分の感想

Javaは言語としてそんなに悪くない

昔と比べるとJava自体も変わったし、Javaを扱うツールやIDEも進化したなぁと思う。 テクノロジーの選定は、視点を広げて、開発環境やエコシステム、ワークフローを含めて考えるようにしたい。

面接は全くうまくいかない。さらに、面接をどう改善すべきか全然分からない

面接を改善するのではなく、インターンや筆記テスト、課題制作などを課すことで、面接で審査すべきことを極力減らすのが良いと思う。

現実的であるために綺麗であることを諦めるのは通常は良い判断である

綺麗さにこだわってしまうのが自分の悪い性癖なので、気をつけたい。

YAGNI、SOLID、DRY。この順序で。

最近、新卒エンジニア教育で教えるようになった。新卒エンジニアの皆さんは割と頑張ってYAGNIに反した物作りをしてしまう傾向にあると思うが、YAGNIとDRYは新人の間に浸透させることが出来たと思う。SOLIDは、多分Sしか理解してもらえていないと思うけど、新人さんには最先端の技術よりもこういう基本的な考えをまずは身に付けてもらいたいと思います。

どんなパラダイムにおいてもダメなコードは書かれる

所属している組織でよくあることだが、使いこなせていないフレームワークで書かれたくそコードの保守がしんどくなってくると、フレームワークが古いことが問題の原因であるとされて、新しいフレームワークへの移行が行われる。

当然、開発者の基本的なスキルが上がっていないわけで、新しいフレームワークを使いこなせるわけでもなく、くそコードがもう一度生産される結果になっている。

くそコードから脱却するには、テクノロジーのせいにするのではなく、ちゃんとしたコードを書ける人を採用したり、教育することが重要だと思う。

あと、こういう系の話は昔読んだソフトウエア開発 55の真実と10のウソという本に調査結果も交えてよくまとめられていたので、組織的な判断をお偉いさんとする場でスッと出せるように読み直しておきたい。

VSCodeでError “command ‘markdown.extension.onEnterKey’ not found”が出るときの対処

目的

  • VSCodeでError “command ‘markdown.extension.onEnterKey’ not found”が出て改行出来ないのをなんとかする

onBackspaceKeyなども同様

方法

    • Markdownファイルを開くのが初めての場合(“Activating Extensions...“というメッセージがステータスバーに表示される)、拡張の読み込みが終わるまで数秒待つ
  • 待ってからでもエラーが出続ける場合、VSCodeをリスタートする
  • それでもダメな場合、Markdown All in Oneのアンインストール、VSCodeのリスタート、Markdown All in Oneの再インストールを行う

参考リンク

YouTubeアプリでオフラインに一時保存済の動画のコメントが見れない時の対処

目的

  • YouTubeアプリで「オフラインに一時保存」した動画は、コメントが見れない場合があるので、その場合にコメントを見れるようにする

方法

  • 虫メガネのアイコンから検索し、該当の動画を結果に表示させる
  • 検索結果から動画をタップし、再生する
  • これで、コメントまでスクロールするとコメントを見ることが出来る

JavaScriptでオブジェクトをマージするには

目的

  • {a:1,b:2}{c:3,d:4}があったとして{a:1,b:2,c:3,d:4}を作りたい

方法

  • スプレッド構文を使う

サンプルコード

let obj1 = {a:1,b:2};
let obj2 = {c:3,d:4};
let merged = {...obj1, ...obj2};

参考リンク

  • スプレッド構文 - JavaScript | MDN

    prototype を除いた浅いコピーの作成や、マージしたオブジェクトの作成が Object.assign() を使うよりも短いコードで書けます。

MacでChromeに切り替えても別のデスクトップに飛ばされなくするには

目的

Macで以下のような問題に対処する

  • ⌘+tabでChromeに切り替える
  • 別のデスクトップに飛ばさる

方法

  • control+↑でmission controlを起動する
  • 右上の「+」で新しいデスクトップを追加する
  • 問題が起きている飛ばされ元のデスクトップのウインドウを追加したデスクトップに全て移す
  • 問題が起きていたデスクトップは「X」で削除する

Prometheusの内部構造 - Prometheusドキュメント

このページはPrometheus公式ドキュメント和訳+αの一部です。

内部構造

Prometheusサーバーは、Prometheus全体の機能を生み出すために協調して一緒に働く多くの内部コンポーネントから成る。 このドキュメントは、それらがどのように組み合わさっているかを含む主要なコンポーネントの概要およびその実装の詳細へのリンクを示す。 もしPrometheusの新米開発者でPrometheusの各部分の概要を知りたいのなら、ここからはじめよう。

このダイアグラムで、Prometheusサーバー全体の構成が示されている。

Prometheus server architecture

: 矢印は、リクエストやコネクションを開始する方向を示し、必ずしもデータの流れの方向ではない。

以下のセクションで、図中の各コンポーネントについて説明する。 コードへのリンクや説明は、Prometheus 2.3.1に基づいている。 Prometheusの将来のバージョンでは異なる可能性がある。

main関数

main() functionは、Prometheusサーバーの他の全てのコンポーネントを初期化し稼働させる。 また、依存関係のあるコンポーネント同士を繋げる。

第一歩として、main()は、サーバーのコマンドラインフラグを定義し、解析してローカルの設定の構造体に変換する。 同時に、サニタイズやいくつかの値の初期化を行う。 フラグに基づくこの設定の構造体は、あとで(--config.fileフラグで指定された)設定ファイルから読み込まれる設定からは独立していることに注意すること。 Prometheusは、フラグに基づく設定とファイルに基づく設定を区別する。フラグは、サーバーの再起動なしに更新することができない単純な設定利用され流のに対し、設定ファイルで提供されている設定項目は、サーバーを再起動せずに再読み込みできなければならない。

次に、main()は、Prometheusの実行時のコンポーネントを初期化し、channelや参照、後の協調動作やキャンセル処理のためのcontextの受け渡しを利用してそれらを接続する。 これらのコンポーネントには、(このドキュメントの残りで説明されているように)サービスディスカバリー、監視対象のスクレイプ、ストレージなどが含まれる。

最後にPrometheusサーバーは、起動とシャットダウンを調整するためにgithub.com/oklog/oklog/pkg/groupを利用して、actorモデルのように全てのコンポーネントを実行する。 順序の制約を為に強制する(ストレージの準備が出来て最初の設定ファイル読み込みが起きるまではwebインターフェースを有効にしないなど)ために、複数のチャネルが利用される。

設定

設定のサブシステムは、--config.fileフラグで指定されたYAMLの設定ファイルで与えられる設定の読み込み、検証、適用を受け持つ。 全ての設定項目の説明はドキュメントを参照すること。 Prometheusには、設定ファイルの読み込みと適用のための機能があり、同じファイルからの設定の再読み込みのリクエストを待ち受けているgoroutineがある。 どちらの仕組みもこの後で説明されている。

設定の読み込みと解析

最初の設定が読み込まれたまたはそれ以降の再読み込みが起きた時に、Prometheusは、config.LoadFile()を呼び出し、設定をファイルから読み込み、解析してconfig.Config structureに変換する。 この構造体は、サーバーとその全てのコンポーネントの設定全体を表す。 これは、設定ファイルの階層構造を反映した下層構造を含んでいる。 各構造体には、デフォルトの設定およびYAMLから構造体へと変換しさらに有効性を検査したり初期化するUnmarshalYAML()メソッドがある。 設定が完全に解析されて検証が終わると、その結果の設定の構造体が返される。

再読み込みハンドラー

設定再読み込みハンドラーは、main()の中で直接実装されているgoroutineであり、webインターフェースまたはシグナルHUP)からの設定再読み込みリクエストを待ち受けている。 再読み込みリクエストを受け取ると、config.LoadFile()を使って上述のように設定ファイルをディスクから読み直し、再読み込みをサポートしている全てのコンポーネントに、ApplyConfig()メソッドを呼び出すか、独自の再読み込み関数を呼び出して、その結果の構造体config.Configを適用する。

終了ハンドラー

終了ハンドラーは、main()の中で直接実装されているgoroutineであり、webインターフェースまたはシグナルTERM)からの終了リクエストを待ち受けている。 終了リクエストを受け取ると、リターンして、github.com/oklog/oklog/pkg/groupで提供されているactor coordinationの機能を通じて、他のPrometheusコンポーネント全てを綺麗に終了させる。

Scrape discovery manager

scrape discovery managerは、discovery.Managerであり、Prometheusのサービスディスカバリー機能を利用して、Prometheusのメトリクス取得元である対象のリストを継続的に更新する。 監視対象を実際にスクレイプをするscrape managerからは独立しで動作し、synchronization channelを通してtarget groupの更新を流す。

内部的には、scrape discovery managerは、設定で定義されたサービスディスカバリーの仕組みのインスタンスをそれ自体のgoroutineで動作させる。 例えば、設定ファイルのscrape_configが2つのkubernetes_sd_configセクションを定義しているとすると、scrape discovery managerは2つの別々のkubernetes.Discoveryインスタンスを動作させる。 これらのkubernetes.Discoveryはそれぞれ、インターフェースdiscovery.Discovererを実装しており、synchronization channelを通して監視対象の更新をdiscovery managerに送信する。 そうすると、discovery managerは、特定のディスカバリーインスタンスについての情報でターゲットグループを拡充し、それをscrape managerに転送する。

設定の変更が適用されると、discovery managerは、動作中のディスカバリーの仕組みを全て停止し、新しい設定ファイルで定義されたものとして再起動する。

さらなる詳細については、広範なサービスディスカバリーの内部についてのドキュメントを参照すること。

Scrape manager

scrape managerは、scrape.Managerであり、検出された監視対象からメトリクスを取得し、得られたサンプルをストレージのサブシステムに転送する。

ターゲット更新と全体の構造

scrape discovery managerが、scrape_configそれぞれに対して1つのディスカバリーの仕組みを動作させるのと同様の方法で、scrape managerはscrape_configそれぞれに対して対応するスクレイプのプールを動作させる。 両者は、複数のリロードとこの2つのコンポーネントにまたがっているscrape_configを、設定項目job_nameを通して特定する(job_nameは1つの設定ファイルの中でユニークでなければならない)。 discovery managerは、scrape_configそれぞれに対する監視対象の更新をsynchronization channelを通してscrape managerに送信する。 scrape managerは、それらの更新を対応するscrape poolに適用する。 各scrape poolは、監視対象それぞれのスクレイプのループを実行する。 全体の階層構造は以下のようになる。

  • Scrape manager
    • Scrape pool for scrape_config 1
      • Scrape loop for target 1
      • Scrape loop for target 2
      • Scrape loop for target 3
      • [...]
      • Scrape loop for target n
    • Scrape pool for scrape_config 2
      • [...]
    • Scrape pool for scrape_config 3
      • [...]
    • [...]
    • Scrape pool for scrape_config n
      • [...]

ターゲットのラベルとリラベル

scrape managerが、あるスクレイプのプールに対する更新された監視対象のリストをdiscovery managerから受け取ると、そのスクレイプのプールは、デフォルトのターゲットラベル(jobinstanceなど)を各ターゲットに適用し、最終的にスクレイプすべき監視対象のリストを生成するためにリラベルの設定を適用する。

ターゲットのハッシュとスクレイプのタイミング

To spread out scrapes within a scrape pool and in a consistently slotted way across the scrape_config's scrape interval, each target is hashed by its label set and its final scrape URL. This hash is then used to choose a deterministic offset within that interval. スクレイプのプール内にスクレイプを拡散し、 scrape_configのスクレイプ間隔に絶えず 各監視対象は、ラベル集合と最終的なスクレイプURLでハッシュが取られる。 このハッシュは、スクレイプ間隔内のオフセットを選ぶために利用される。

監視対象のスクレイプ

最後に、スクレイプのループは、定期的に、HTTPで監視対象をスクレイプし、受信したHTTPレスポンスをPrometheusのテキストベースのメトリクス出力フォーマットに従ってデコードする。 個々のサンプルそれぞれにメトリックのリラベル設定を適用し、その結果のサンプルをストレージのサブシステムに送信する。 さらに、複数のスクレイプの実行にまたがる時系列の失効を追跡し保存し、スクレイプの状態の情報upscrape_duration_secondsなどのメトリクス)を記録し、ストレージエンジンへの時系列の追加を最適化するためのデータの整理を行う。 1回のスクレイプは、設定されたスクレイプ間隔より時間がかかってはいけないし、スクレイプのタイムアウトはそれが上限になっていることに注意。 これによって、1回のスクレイプが別のスクレイプが始まる前に終わらされるのが確実になる。

ストレージ

Prometheusは、時系列のサンプルをローカルの時系列データベース(TSDB)に保存し、オプションで、全サンプルのコピーを設定されたリモートのエンドポイントに転送する。 同様に、Prometheusは、ローカルのTSDBおよびオプションでリモートのエンドポイントからデータを読み取る。 ローカルとリモートのストレージのサブシステムについて以下で説明する。

fanoutストレージ

fanout storageは、他のコンポーネントによる利用のために、背後にあるローカルおよびリモートのストレージの詳細をプロキシ、抽象化するstorage.Storageの実装である。 読み込みのためにローカルとリモートの読み込み元からのクエリの結果をマージし、書き込みはローカルとリモートの全ての書き込み先に複製される。 時系列の取り込みを最適化するための機能は様々なので、内部的には、第1の(ローカルの)ストレージとオプションの第2の(リモートの)ストレージを区別する。

現在、ルールはまだ、直接、fanout storageから読み込み、fanout storageへ書き込みをしているが、しばらくすると、デフォルトでルールがローカルデータを読みこむだけになるように変更されるだろう。 これで、ほとんどの場合で短期のデータしか必要のないアラートとレコーディングルールの信頼性が増す。

ローカルストレージ

Prometheusのローカルディクス上の時系列データベースは、github.com/prometheus/tsdb.DBに対する軽量ラッパーである。 このラッパーは、Prometheusサーバー環境でTSDBを利用するための若干のインターフェースの調整だけをし、storage.Storageインターフェースを実装する。 ローカルストレージのドキュメントにTSDBのディスク上のレイアウトさらなる詳細がある。

リモートストレージ

リモートストレージは、remote.Storageであり、storage.Storageインターフェースを実装し、リモートの読み込みと書き込みのエンドポイントとの連結を担っている。

設定ファイルのremote_writeそれぞれに対して、remote storageは1つのremote.QueueManagerを作成し、動作させる。 次に、remote.QueueManagerは、サンプルをキューに入れ、リモートの書き込みエンドポイントに送信する。 各キューマネージャーは、現在と過去の負荷の観察に基づいて動的に決まる数のシャードを動作させることで、リモートエンドポイントへの書き込みを並列化する。 設定の再読み込みが適用されると、全てのリモートストレージのキューはシャットダウンされ、新しいキューが作成される。

設定ファイルのremote_readそれぞれに対して、remote storageは1つのreader clientを作成し、各リモートソースからの結果はマージされる。

PromQLエンジン

PromQLエンジンは、PromQL expression queriesのPrometheusの時系列データベースに対して評価する役割を担っている。 このエンジンはそれ自身アクターのgoroutineとして動作せず、webインターフェースとルールマネージャーからライブラリとして利用される。 PromQLの評価は、複数の段階を経る。クエリが作成されると、その式は抽象的な構文木へとパースされ、実行可能なクエリとなる。 後続の実行段階では、背後のストレージから得られる必要な時系列を検索し、そのためのイテレーターを作成する。 時系列の大量データの実際の取得は、(少なくともローカルのTSDBの場合は)評価時に行われる。 式の評価は、PromQLの式の型(ほとんどの場合はinstant vectorまたはrange vector)を返す。

Rule manager

rule managerは、rules.Managerであり、(設定ファイルのevaluation_intervalで設定されているように)定期的なレコーディングルールとアラートルールの評価をする役割を担っている。 各繰り返しで、PromQLを利用して全てのルールを評価し、結果の時系列をストレージに書き込む。

アラートルールに関しては、rule managerは、以下のように、各繰り返しでいくつかのことを行う。

  • pendingまたはfiringのアラートに対して時系列ALERTS{alertname="<alertname>", <alert labels>}を保存する
  • アラートルールのforの時間に基づいて、pendingからfiringにいつ遷移するか決めるためにactiveなアラートのライフサイクルの状態を追跡する
  • activeなアラートそれぞれに対してアラートルールのラベルとアノテーションのテンプレートを展開する
  • firingなアラートをnotifierに送り(下記参照)、解消したアラートは15分間送り続ける

Notifier

notifierは、notifier.Managerであり、rule managerが生成したアラートをSend()メソッドで受け取り、キューに入れ、設定されたAlertmanagerインスタンス全てに送信する。 notifierは、アラートの生成とアラートのAlertmanagerへの送信(失敗したり時間がかかったりする)を分離する役割を果たす。

Notifier discovery

notifier discovery managerは、discovery.Managerであり、Prometheusのサービスディスカバリーの機能を利用して、notifierがアラートを送るAlertmanagerのインスタンスのリストを検索し継続的に更新する。 notifier discovery managerは、notifier managerとは独立して動作し、synchronization channelを通してtarget groupの更新を次々にnotifier managerに送信する。

内部的には、scrape discovery managerと同様な仕組みで動作する。

Web UI and API

Prometheusは、デフォルトでは9090ポートでweb UIとAPIを提供する。 web UIは/で利用可能であり、クエリを実行したり、activeなアラートを調査したり、その他のPrometheusサーバーの状態を理解するために人間が利用するインターフェースとして機能する。

web APIは、/api/v1で提供され、クエリ、メタデータ、サーバーの状態をプログラムで調べることを可能にしている。

コンソールテンプレートは、TSDBデータにアクセスできるユーザー定義のHTMLテンプレートをPrometheusが提供出来るようにするものであり、設定されていれば/consolesで利用可能である。

参考リンク

おすすめ書籍

入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング

入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング

入門 監視 ―モダンなモニタリングのためのデザインパターン

入門 監視 ―モダンなモニタリングのためのデザインパターン

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム