Hurl HTTPリクエストのテストがプレーンテキストで超手軽に!?
引用元:https://news.ycombinator.com/item?id=44324592
Hurlは数ヶ月前から使い始めたんだけど、テストスイートモードと個別実行モードがあるのがマジで良いね。CIでサービスのHTTPリクエストのテストスイートを実行するのに使ってるよ。設定言語はちょっとファンじゃないかな、ブロックが直感的じゃないし、ドキュメントに記載されてないアサーションもあると感じたんだ。全体的にはツールは素晴らしくて、すごく valuable だったよ。POCsで interface testing を始めた時に使ってみたんだけど、これがLLM開発に役立つって気づいたんだ。テストがHTTPメソッドを直接実行するように書かれてるから、プロジェクトが進むにつれて実装の柔軟性と進化ができるんだ。テストを分離するのもすごく役に立ったし、interface と implementation の分離がさらに徹底される感じ。Hurlの前は、サービスの言語のテストフレームワークでテスト書いてたんだ。Hurlベースのテストはマジで”client”視点を徹底するのに役立つね。バックドアのデータアクセスとか全然なくて、interface、テスト、implementation の間に厳格な分離があるんだ!
Hurlのメンテナーだけど、フィードバックありがとう!6、7年前にHurlを作り始めた時は、最初はJSONとかYAMLファイル形式だったんだ。だんだん新しいファイル形式を書く方が良いって確信したんだけど、それがちょっと変に感じるかもしれないってのは完全に理解できるよ。シンプルなケースはシンプルになるようにトライしたんだけど(もしかしたら成功してないかも!)。ドキュメントに関する問題には本当に興味があるから、どんな問題でも大歓迎だよ!いつでも改善できるからね!
Yeah、Hurl大好き!2023年9月から使い始めたんだ。前はRunscopeでテストスイート使ってたんだけど、変更がバージョン管理されないのがマジで嫌だった。AI助けて!って思いながらちょっと頑張ってRunscopeのテストを全部Hurlに変換したんだ。今は誰がどんな変更をいつ、なんでしたのか全部わかるようになった!マジ最高。
私もRunscopeの変更がバージョン管理されなかったの嫌いだったんだ :) その作業は始めたんだけど、その後なんか違う方向に行っちゃって。
Oh wow、まさかここでRunscopeの創設者に出会うとはね。Runscopeは目的を果たしてくれたんだけど、バージョン管理ができるのが出てきちゃったんだよね。
Hi Hurlメンテナーです、質問があれば喜んで答えるしフィードバックも大歓迎だよ!
ねぇ、私とか知り合いの多くは、VS CodeやIDEAのIDE拡張で実行できる”.http”ファイルの形でテストを書いてるんだ。あれって、
POST http://localhost:8080/api/foo
Content-Type: application/json
{ ”some”: ”body” }
みたいな形式でしょ?それと、integration test 用に”expected.json”っていう出力の1対1マッピングがあるんだ。これらをbashスクリプトでcURLで実行して、jqで出力を比較、成功・失敗をコンソールにログして、”actual.json”を書き出すってやってるんだ。HURLでも同じような使い方はできる?要するに、期待する出力としてJSONファイルを参照する、IDEで実行可能なサンプルHTTPリクエストみたいな感じで?あと、それらのファイルのディレクトリ全体に対してHURLを実行することはできる?
Hurlでそのやり方はできるよ。僕のプロジェクトでは、testディレクトリにHurlファイルを置いてて、テストケースごとに1ファイルになってるんだ。1つのケースで1つ以上のHTTPリクエストを実行できるよ。Hurlファイルは外部ファイルを参照したり、レスポンスから値を取得して後続のリクエストに使ったり、ステータスや出力のバリデーションもできるんだ。Hurlには色々なテストランナーモードがあって、もしもっと大きなレポートフレームワークと連携したいなら、全体の結果を解析可能な色々なフォーマットで出力することもオプションで選べるよ。
それができるって聞いてマジ嬉しい!もしよかったら手元に例とかある?
もしそれができるなら、たぶん唯一お願いしたいのは、VS CodeやJetBrainsのIDEがサポートしてるREST Clientの”.http”ファイルとの相互運用性かな。UPDATE: 見つけた!下の方法でできるみたいだね。
POST https://example.org/api/tests
Content-Type: application/json
file,insert_user.request.json;
[Asserts]
body == file,insert_user.expected.json;
ってことだと、あとはIDE連携だけだね。
そのアプローチ良いね。あなたのexpected.jsonは実際のレスポンスボディなの?それともボディ、ステータス、ヘッダーの値、時間などを含むオブジェクト?
Hurlはレスポンスボディしか検証しないけど、俺にはそれで十分。APIドキュメント、テスト、開発中のAPI呼び出しに便利だから気に入ってるぜ。
HurlはメンテナブルなHTTPテスト書くのに過小評価されてるよな。良いツールだぜ、ありがとう!
VSCodeのrest clientの開発者と協力して、httpファイルの標準仕様を作ったらどうだ?
ちょっと脱線するけど、Hurlって名前の響きが最高に気に入ってるんだ。
メンテナンスお疲れ様! Hurlは今後2年でどうなると思う?
IDE連携、gRPC、Websocketサポートは良いね。個人的にはaptで入るのが一番嬉しいな。Debianへの対応がマジで難しくて手こずってるんだよ。
https://github.com/Orange-OpenSource/hurl/issues/366
Fedoraパッケージもないみたいだな。もし時間できたら、specファイルとかci/cdワークフローを提供して、そっちでも使えるように手伝えるかもよ。
Hurlは使ってるし貢献もしたことあるぜ。設定ファイルのインクルード機能、実現できそう?
Hurlはマジで最高! PythonからRustにサービス移した時、HurlのテストのおかげでAPI変えずにできたんだ。Rustで使うとcargo testとも連携できて、.hurlファイルがそのままテストに使えるのが激アツだよ! デモはこれ。
https://github.com/perrygeo/axum-hurl-test
正直言うとね、あのサンプル section[1] はツールの良さを伝えるのに超うまいやり方だと思ったよ。
特に最初の5分でパッと判断しちゃう人には響くはず(俺もたまにやっちゃうけど)。
[1] https://github.com/Orange-OpenSource/hurl?tab=readme-ov-file…
俺が自分のHTTPテストツール「Nap」[0]をデザインする時、このHurlからめっちゃインスピレーションもらったんだ。
何百ものテストを速く、並列に実行する必要があったからね。
もしそういうのが必要で、Hurlが気に入ったなら、Napも気に入るかも。
[0] https://naprun.dev
そのNapの設定って、Hurlと一緒?違う?似てる?
違いをまとめたページとかあるの?教えてほしいな。
一番の違いはね、NapはYAMLで動くことだよ。
どんな感じかは、ページの左側にある「The Basics」[0]をクリックすると見れるよ。
[0] https://naprun.dev/the-basics/
なんか、これってこのVS Codeの拡張機能にちょっと似てるね。
https://marketplace.visualstudio.com/items?itemName=humao.re…
HTTPとか色々テストするのに超使えるやつだよ。
IntelliJにも同じような機能あるよ。
https://www.jetbrains.com/help/idea/http-client-in-product-c…
https://github.com/mistweaverco/kulala.nvim
Neovimには「kulala.nvim」っていう別のrestish系(gRPCもできる)プラグインもあるよ。
Jetbrainsのにできるだけ互換性を持たせようとしてるみたい。
Neovimにもあるんだって!「rest.nvim」[0]っていうやつ。
職場の人がIntelliJの使ってるの見てから、Neovimで探したんだけど、これが一番良かったな。完璧じゃないけど、ちゃんと動くよ。
あ、でも記事のHurlも超 neat だね。試してみるわ。いくつかよく使うテスト用に用意しておくのに便利かも。
[0] https://github.com/rest-nvim/rest.nvim
そうそう、エディタに依存しないってのが、個人的には超デカいメリットだと思う。
あとBrunoとBruってのもあるんだよね。
これもHurlに結構似てるみたいだよ。
https://docs.usebruno.com/bru-lang/overview
ただ、これはPostman使う人向けっぽいから、Hurlほど軽量じゃないかもね。
Postmanとかそれに似たツールは全然軽量じゃないし、Postmanとその騒動は置いといても、データをインポート・エクスポートしないとリポジトリにコミットできるテキストファイルにならないのが大きな欠点なんだ。うちのチームではこれがだめで、みんながテストスイートを作ってもコミットしないから、他の人が同じ作業を何度もやっちゃうんだよ。
もっとコメントを表示(1)
Brunoならテキストファイルのためにインポートやエクスポートは必要ないよ。
あああ、わかった。Insomniaと混同してたかも。あれもPostmanのフォークかな?どっちにしても、テキストファイル問題がPostmanがだめだった理由だよ。Rest Clientは設定がテキストファイルなのも良いね。bearer tokenとかをスクリプトで更新できる。でもRest Clientにもリクエストチェインとか欠点はあるけど。
Brunoでも設定はテキストファイルだよ。Rest Client使ってたけど、コンピュータのNO_PROXY環境変数を使って特定のURLでプロキシを回避したかった時、それができなくて困ったんだ。それで他のツールを探すことになった。分析の結果、BrunoとHurlが良い感じだった。Hurlはまだ試してないな。
うん、Hurlは触ってみて良かったけど、最近は.httpファイル形式に惹かれてるんだ。IntelliJには組み込みであるし、リンクされてたプラグインもあるし、CLIならhttpYacを使ってる。ベンダーロックインがないし、コピペやソース管理で簡単に共有できるのが最高だね。
HttpYacには+1だね。使い始めやすくて、だんだん強力なAPIテストスイートとして成長させられるのが本当に良いよ。
アイデアは良いと思うけど、なんでこれを使うべきか悩むね。僕はDjangoを書いてて、フレームワーク内に十分なテスト機能があるんだ。なんでバックエンドに盲目で、同期の手間が増えるツールに切り替えるんだろう?少なくとも、結果がおかしい時にデバッガーで簡単に調べられなくなる。バックエンドとテストコードを明確に分けるメリットもあるだろうけど、これだと作成・保守が大変になりそう。ネイティブのテストスイートも結局必要だし、外部ツールに手を出すのは少し変な感じがするな。APIが十分に汎用的で、他の人もクライアントを実行できるようにするためだけならありえるけど。
バックエンドに盲目で、同期の手間が増えるツールか。僕はHurlは使ってないけど、言語非依存のAPIテストツールはいくつか使ったことがあるし、今も新しいのを作業中だよ。こういうテストの良いところは…実装に盲目なこと、むしろそれが利点なんだ。内部に依存せず、インプットとアウトプットだけを見れるからね。言語非依存で共有しやすいから、ドキュメントとしても使えるし、OpenAPI specに加えて、または代わりにチーム間で共有するのにすごく良い。それに実際に契約をテストしてるから、移行の時にも再利用できるんだ。PerlからGoへの大規模なAPI移行で、既存のPerl APIのテストを非回帰テストとして書いて、Go APIでも全く同じテストを使えたから、書き直すよりずっと自信が持てたよ。開発者としても、これらを書くことで文脈を切り替えて、自分が作ったAPIの消費者になれるから、質の高いテストを書きやすかったな。
これはPostmanとかの代替だよ。HTTPリクエストをいくつかテストするためだけに、重たいElectronウィンドウを丸ごと起動する必要がなくなるんだ。curlスクリプトとPostmanの中間くらいの位置づけで、多くの人にとってちょうど良いところをついてるんだよ。
うちではHurlを使って、ktorのWebサーバーからSpring Bootに書き換えたんだ(Java/Kotlinスタック)。サーバーのスタックに依存しない仕様テストスイートがあったおかげで、移行がすごく楽だったよ。もう一つの利点は、プロダクション用にDockerイメージをビルドしたんだけど、結合テストのために軽量で実装に縛られないものが欲しかったんだ。それにHurlが役立ったね。
Hurlは必須じゃないし、もっと良いツールがあればそっちでいいよ。でも、チームで使うなら追加モジュールとかvenvがいらない自己完結型ツールはめちゃくちゃ便利。みんな簡単に使えるようになるし、起動も速いだろうね。特にヘッダーテストは、ウェブサーバーやLB、CDNの設定確認に役立ちそうだよ。
面白いね。昔はVS Code-restclient使ってたけど、最近はスクリプトやCLI用にhttpyacに移ってるんだ。Hurlも試してみるよ。でも、こういうツールを使ってて困るのが、.http
ファイルで前のリクエスト結果を次の入力にする構文に標準がないこと。Hurlは[Captures]
、VS Code-restclientは{{loginAPI.response.body.token}}
、httpyacは@ref
って全部バラバラなんだよね。どれか一つに合わせると他で動かなくなりそう。
[1] https://hurl.dev/docs/capturing-response.html
[2] https://github.com/Huachao/vscode-restclient
[3] https://httpyac.github.io/guide/metaData.html#ref-and-forcer…
またHTTPクライアント用の新しいフォーマット作っちゃって、ごめんね!
この問題に対処するために、Hurlと一緒に使えるhurlfmt
っていうツールがあるよ。HurlファイルをJSONにエクスポートできるんだ。JSONを介せば他の形式にも変換できるかも。魔法じゃないけど、Hurlから別のツールに移る時にちょっとは役立つと思うよ。
大丈夫、みんながどんな構文が良いと思ってるか見るのも面白いね。エクスポート・インポートツールがあると、確かにちょっと楽になるかも。標準化の仕組みやきっかけは分からないけど、多分すごく良いツールが出てみんなが真似したくなる時かな。とにかく、返信ありがとう。ツール頑張ってね。
すごいのは、Visual Studio CodeとVisual Studioの両方に.HTTP
ファイルがあるのに、互換性がないってことだよ。 みなさん、これがConway’s Law(コンウェイの法則)の実践例だね。
JVMプロジェクトでは、結合テストにKarateを使ってるよ。 https://github.com/karatelabs/karate
テストシナリオに好きなJavaScriptを書けるから、リクエストや検証を自由に設定できるんだ。
IntelliJにあるHTTP Clientツールに似てるんじゃない? https://www.jetbrains.com/help/idea/http-client-in-product-c…
似てるかもしれないけど、IDEのプラグインではないよ。
単体でも使えるみたいだよ。 https://blog.jetbrains.com/idea/2022/12/http-client-cli-run-…
こういうシンプルでCLIで使えるツール、すごく良いね! https://httpie.io/cli とか https://jqlang.org/ を思い出したよ。
Nice editor integration(特にEmacs)があれば、HurlはPostmanのいい代わりになるね。ちょっとニッチだけど、俺はlibhurlをラップしてAWS Lambdaの可用性モニターを超簡単に作れるようにしたよ。このHurlファイルからね→ https://gitlab.com/manithree/hurl_lambda
面白そうだね。依存ライブラリを見てみたんだけど、HTTPコールとかをテストするCLIツールで1.5k行って、Rustだと普通なの?このURL見てよ→ https://github.com/Orange-OpenSource/hurl/blob/master/Cargo….
依存関係はCargo.lockじゃなくてCargo.tomlファイルを見た方がいいんじゃないかな(直接の依存だけでもね)。lockファイルには開発やテスト用の依存も入っちゃうからさ。
Hurlに足りないのはスナップショットテストだね。insta
でAPIテストしてから、もうそれに慣れちゃって他の方法に戻れないよ。
それってhttps://insta.rs/のこと?スナップショットテストでどんなメリットを感じた?教えてよ。
定型コードがめっちゃ減るんだよね。スナップショットの差分を見て変更を承認するか拒否できるのが、より堅牢でユーザーフレンドリーだよ。
スナップショットの価値って何?body全体をチェックするんじゃダメなの?HurlのREADMEにも色々書いてあるじゃん→ https://github.com/Orange-OpenSource/hurl?tab=readme-ov-file…
スナップショットは現在の出力と前回の差分を見るんだ。俺がするのはその差分をOKかNGするだけ。期待する応答を自分で全部書かなくていいんだよ。非決定的な部分(日付とか)もマスクできるしね。
非決定的な部分をマスクできるんだ!知らなかった!俺はそれをモックでやってたよ。スナップショットテストがそういう非決定的な部分を”マスク”できるって聞くと、超クールだね!
正直、それってかなりスナップショットテストに近いと思うよ。APIテストだけじゃなく、俺は今TUIアプリのテストにも使ってる。「なんか出力があって、それを表示できるなら、将来変更するまで同じ見た目であるべき」っていうテストなら使える。最初のスナップショットを自分で書かなくていいのも便利だよ!
Kreyaっていうツールでもスナップショットテストを開発中だよ。8月に出る予定だから、チェックしてみて!
もっとコメントを表示(2)
Hurlのフォーマットで、レスポンスのステータスコードのアサーションがなんで[Asserts]じゃなくてリクエストのところに書くのか、それがずっと謎なんだよね。理由は何なんだろう?
ひとつ前のコメントへの回答だよ。
簡単なGETでステータスコードを書くなら、
GET http://foo.com
HTTP 200
って書けばOK。
[Asserts]セクションで
GET http://foo.com
HTTP *
[Asserts]
status == 200
って書くこともできる。
HTTP行はレスポンスセクションの区切りになってるんだ。
自分のRADテンプレートWebサーバープロジェクトでHurlがテストにすごく役立ってるよ。Hurlベースのテストのおかげで「クライアント視点」が強化されるって話、ほんとそう。Dockerイメージ含め3つの環境でテストしてるけど、Hurlで全部クライアントレベルのテストが簡単にできるんだ。
欲を言えば、もっと高機能な正規表現が欲しいな。regexクレート(とHurl)は後方参照ができないから、特定のパターンチェックができなかった。あと、ストリーム更新やSSEのテスト方法があれば最高なんだけど。コネクション開いて待機、別のリクエスト、元のコネクションのストリームをアサート、みたいな。詳細はこのリンク見て。https://github.com/Orange-OpenSource/hurl/discussions/2636
自動テストにはHurlを使ってるんだけど、個人的には別のツールを開発したいと思ってるんだ。Hurlのクライアントの状態管理がイマイチで、そこを直すのは簡単じゃない。もっと完全にクライアントの状態を制御できて、変数管理も使い方も良くしたいんだよね。前のプロジェクトではPythonでテスト書いたけど、最初は良かったけど継続メンテでどうなるか分かんないな。
すごく興味深いツールだね。俺も似たようなことをやったことがあるんだ。VS Code Rest-client(https://marketplace.visualstudio.com/items?itemName=humao.re…)のファイル向けにCLIモードのインタープリターを実装したんだ。HTTP操作の結果に対してJavaScriptでテストコードを実行できる機能も付けたよ。バッチモードで.httpファイルをまとめて実行したり、選んだHTTP操作を並列で実行できるツールにしたかったんだ。
これ良さそうだね。もしWebSocketサポートが追加されたらテストに使ってみたいよ。詳細はここ見て。https://github.com/Orange-OpenSource/hurl/issues/1096
いいね。これ、Goで書かれたこのツール(https://github.com/vdobler/ht hjsonを使ってる)よりずっと良さそうだ。数年前にかなり使ってたんだ。Hurlを試してみるつもりだよ。
READMEのPOST例、パスワードをクエリパラメーターで送ってるの?省略記法?それとも文字通り?
俺はcurlの代替はあんまり必要ないかな。前はhttpieとか使ってたけど、結局Pythonのrequestsライブラリでテスト書くのに戻っちゃうんだよね。
もしかしたら俺はターゲットじゃないのかもだけど、何か良いこと言っとくべきかな。Rust製なのは良いね。AIのモノリスに仕事全部スクレイピングされる時代になって、OSSツールには新しいプロジェクトが必要とされてるから、こういうのは祝うべきだよ。ただ、俺には使いどころがないのが残念だけど。
READMEのPOSTは、リクエストボディで”url form encoded”形式、ウェブページのフォームみたいにパラメーターを送るんだよ。ドキュメントサイトにもっとサンプルがあるよ [1]。
curlに関して言うと、Hurlはリクエスト間でデータを渡したり、レスポンスにアサートを追加するための構文をcurlに足してるだけなんだ。一度送って終わり、みたいなリクエストならcurlで十分だけど、認証が必要なリソースにアクセスするみたいなワークフローがあるならHurlは試す価値あり。Hurlは内部でlibcurlを使ってて、--curl
オプションでcurlコマンドリストを見ることもできるよ。
[1]: https://hurl.dev/docs/samples.html
READMEのPOSTリクエスト例さ、フォームみたいにボディにパラメータ送るってこと?
それともこの例のuserとpasswordをボディで送るって言ってるの?
POST https://example.org/login?user=toto&password=1234
これってマジ?どうやってクエリ文字列パラメータ入りのPOSTリクエスト送るの?
[Form]パラメータのドキュメント[1]だと、フォームエンコードされたリクエストパラメータ送るには明示的な構文があるって書いてあるよ?
[1]: https://hurl.dev/docs/request.html#form-parameters
ごめんね、両方とも。READMEのサンプルはずっと前(4年前)からあって、ちゃんと読み直してなかったんだ。
POST https://acmecorp.net/login?user=toto&password=1234
これはREADMEにある、userとpasswordパラメータをURLに入れたPOSTリクエストだよ。
POST https://acmecorp.net/login
[Form]
user: toto
password: 1234
これはもっと一般的な、userとpasswordをボディに入れたPOSTだよ。多分READMEのサンプル更新すると思う。Issueはここで作ったよ。[1]
[1]: https://github.com/Orange-OpenSource/hurl/issues/4151
これってcurlっていうよりPostmanの代わりになると思うんだ。APIのセットで作業してる時、すぐにHurlファイル書いて色んな組み合わせを試せるんだよね。エディターの連携で個別のリクエストを実行できることが多いし。で、同じHurlファイルをチームで共有したり、リポジトリにコミットしたりできるんだ。
もしPython使いならtavernをチェックしてみてよ。宣言的にAPIテスト書くのに結構いい感じだよ。
これマジでawesomeだね。こんなの何回も探してたし、作るの途中で投げ出したこと何回もあるんだよ。マジ素晴らしい仕事!
俺だけ?それともこれ、https://github.com/Sanix-Darker/dycow からインスピレーション受けたんじゃないかな?
テスト間で「fixtures」って共有できるの?例えば、何百ものテストでユーザーごとにサインアップとログインのプロセスをコピペしたくないんだけど。
テストの分離はどうやる?
テストを実行する前後にサービスを「prime」するのに何か他のツール使ってる?
俺も似てるけどちょっと違うの作ったよ。
サポートしてるどのクローラーでもGETリクエスト投げて、結果をJSONで取得するやつ。
https://github.com/rumca-js/crawler-buddy/
request, selenium, Httpx, curl cffiとか対応してるよ。
元祖Hurl HTTPツールに敬礼!https://web.archive.org/web/20100112040154/http://hurl.it/
うわー!これ、10年くらい前に俺がやろうとしてたことにめっちゃ似てるんだよね。あの頃はノープランすぎてダメだったけどさ。https://github.com/zackify/legible
環境変数とかプロファイルとか、グローバル変数を変えて使えたりするの?
うん、envファイルを使えるよ。リクエストファイルでテンプレート構文を使うんだ。
https://hurl.dev/docs/templates.html#injecting-variables
これクールだけど、素朴な疑問なんだけどさ、なんでHTTP呼び出しも簡単なスクリプト言語じゃなくてこれを使うの?DSLってPLより格段に楽なわけじゃないし、制限もあるよね?生の速度とかDSLの読みやすさのため?
> curlスクリプトとPostmanの中間くらいか。Emacsのrestclient-modeにすごく似てるね。Emacsを開いてない人には確かに魅力的なのが分かるわ。
PostmanユーザーでOrg ModeとEvilを使ってるんだけど、Emacsのrestclient-modeについて教えてくれない?
restclientじゃなくてOrg-modeだよ。コード動かして結果を連携できる文芸的プログラミング環境なんだ。APIテストでob-httpとか使って、結果をClojureやPython、Javascript、Rブロックに渡してJSON処理、SQL DBクエリも。実験が再現可能でノートに残るのが良い。検索、エクスポートも簡単だし、PDFや動画リンク、LLM、Anki連携も。全部Org-modeで完結だよ。
ありがとう。文字通り売ってくれって意味じゃなくて、どうワークフローに合うか説明して欲しかったんだ。ちゃんと伝わったよ。
Org modeは簡単な個人ノートで使ってる。帰ったらRESTクライアントとして使ってみるよ。EmacsはすごいOSだけど、まともなテキストエディタがないっていつも言われてるよね。
もちろん。Org modeソースブロック間でデータを渡す実例だよ¹。Emacsも好きだけど、Org-modeは本当に宝物だわ。もっと早く知りたかった。最高のツールだよ。仕事ノート、個人ジャーナル、Org-Roam、LLMチャット、研究、学習、Anki、pomodoro、dotfiles管理、全部Org-mode。プレーンテキストの価値は過小評価されてる。一度分かると手放せないよ。___¹ https://www.reddit.com/r/emacs/comments/1hbi751/passing_data…² https://news.ycombinator.com/item?id=44264368